]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/FacebookSSO/extlib/facebookapi_php5_restlib.php
- Some reorganizing
[quix0rs-gnu-social.git] / plugins / FacebookSSO / extlib / facebookapi_php5_restlib.php
1 <?php
2 // Copyright 2004-2009 Facebook. All Rights Reserved.
3 //
4 // +---------------------------------------------------------------------------+
5 // | Facebook Platform PHP5 client                                             |
6 // +---------------------------------------------------------------------------+
7 // | Copyright (c) 2007-2009 Facebook, Inc.                                    |
8 // | All rights reserved.                                                      |
9 // |                                                                           |
10 // | Redistribution and use in source and binary forms, with or without        |
11 // | modification, are permitted provided that the following conditions        |
12 // | are met:                                                                  |
13 // |                                                                           |
14 // | 1. Redistributions of source code must retain the above copyright         |
15 // |    notice, this list of conditions and the following disclaimer.          |
16 // | 2. Redistributions in binary form must reproduce the above copyright      |
17 // |    notice, this list of conditions and the following disclaimer in the    |
18 // |    documentation and/or other materials provided with the distribution.   |
19 // |                                                                           |
20 // | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR      |
21 // | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
22 // | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.   |
23 // | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,          |
24 // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT  |
25 // | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
26 // | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY     |
27 // | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT       |
28 // | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF  |
29 // | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.         |
30 // +---------------------------------------------------------------------------+
31 // | For help with this library, contact developers-help@facebook.com          |
32 // +---------------------------------------------------------------------------+
33 //
34
35 include_once 'jsonwrapper/jsonwrapper.php';
36
37 class FacebookRestClient {
38   public $secret;
39   public $session_key;
40   public $api_key;
41   // to save making the friends.get api call, this will get prepopulated on
42   // canvas pages
43   public $friends_list;
44   public $user;
45   // to save making the pages.isAppAdded api call, this will get prepopulated
46   // on canvas pages
47   public $added;
48   public $is_user;
49   // we don't pass friends list to iframes, but we want to make
50   // friends_get really simple in the canvas_user (non-logged in) case.
51   // So we use the canvas_user as default arg to friends_get
52   public $canvas_user;
53   public $batch_mode;
54   private $batch_queue;
55   private $pending_batch;
56   private $call_as_apikey;
57   private $use_curl_if_available;
58   private $format = null;
59   private $using_session_secret = false;
60   private $rawData = null;
61
62   const BATCH_MODE_DEFAULT = 0;
63   const BATCH_MODE_SERVER_PARALLEL = 0;
64   const BATCH_MODE_SERIAL_ONLY = 2;
65
66   /**
67    * Create the client.
68    * @param string $session_key if you haven't gotten a session key yet, leave
69    *                            this as null and then set it later by just
70    *                            directly accessing the $session_key member
71    *                            variable.
72    */
73   public function __construct($api_key, $secret, $session_key=null) {
74     $this->secret       = $secret;
75     $this->session_key  = $session_key;
76     $this->api_key      = $api_key;
77     $this->batch_mode = FacebookRestClient::BATCH_MODE_DEFAULT;
78     $this->last_call_id = 0;
79     $this->call_as_apikey = '';
80     $this->use_curl_if_available = true;
81     $this->server_addr =
82       Facebook::get_facebook_url('api') . '/restserver.php';
83     $this->photo_server_addr =
84       Facebook::get_facebook_url('api-photo') . '/restserver.php';
85
86     if (!empty($GLOBALS['facebook_config']['debug'])) {
87       $this->cur_id = 0;
88       ?>
89 <script type="text/javascript">
90 var types = ['params', 'xml', 'php', 'sxml'];
91 function getStyle(elem, style) {
92   if (elem.getStyle) {
93     return elem.getStyle(style);
94   } else {
95     return elem.style[style];
96   }
97 }
98 function setStyle(elem, style, value) {
99   if (elem.setStyle) {
100     elem.setStyle(style, value);
101   } else {
102     elem.style[style] = value;
103   }
104 }
105 function toggleDisplay(id, type) {
106   for (var i = 0; i < types.length; i++) {
107     var t = types[i];
108     var pre = document.getElementById(t + id);
109     if (pre) {
110       if (t != type || getStyle(pre, 'display') == 'block') {
111         setStyle(pre, 'display', 'none');
112       } else {
113         setStyle(pre, 'display', 'block');
114       }
115     }
116   }
117   return false;
118 }
119 </script>
120 <?php
121     }
122   }
123
124   /**
125    * Set the default user id for methods that allow the caller
126    * to pass an uid parameter to identify the target user
127    * instead of a session key. This currently applies to
128    * the user preferences methods.
129    *
130    * @param $uid int the user id
131    */
132   public function set_user($uid) {
133     $this->user = $uid;
134   }
135
136
137   /**
138    * Switch to use the session secret instead of the app secret,
139    * for desktop and unsecured environment
140    */
141   public function use_session_secret($session_secret) {
142     $this->secret = $session_secret;
143     $this->using_session_secret = true;
144   }
145
146   /**
147    * Normally, if the cURL library/PHP extension is available, it is used for
148    * HTTP transactions.  This allows that behavior to be overridden, falling
149    * back to a vanilla-PHP implementation even if cURL is installed.
150    *
151    * @param $use_curl_if_available bool whether or not to use cURL if available
152    */
153   public function set_use_curl_if_available($use_curl_if_available) {
154     $this->use_curl_if_available = $use_curl_if_available;
155   }
156
157   /**
158    * Start a batch operation.
159    */
160   public function begin_batch() {
161     if ($this->pending_batch()) {
162       $code = FacebookAPIErrorCodes::API_EC_BATCH_ALREADY_STARTED;
163       $description = FacebookAPIErrorCodes::$api_error_descriptions[$code];
164       throw new FacebookRestClientException($description, $code);
165     }
166
167     $this->batch_queue = array();
168     $this->pending_batch = true;
169   }
170
171   /*
172    * End current batch operation
173    */
174   public function end_batch() {
175     if (!$this->pending_batch()) {
176       $code = FacebookAPIErrorCodes::API_EC_BATCH_NOT_STARTED;
177       $description = FacebookAPIErrorCodes::$api_error_descriptions[$code];
178       throw new FacebookRestClientException($description, $code);
179     }
180
181     $this->pending_batch = false;
182
183     $this->execute_server_side_batch();
184     $this->batch_queue = null;
185   }
186
187   /**
188    * are we currently queueing up calls for a batch?
189    */
190   public function pending_batch() {
191     return $this->pending_batch;
192   }
193
194   private function execute_server_side_batch() {
195     $item_count = count($this->batch_queue);
196     $method_feed = array();
197     foreach ($this->batch_queue as $batch_item) {
198       $method = $batch_item['m'];
199       $params = $batch_item['p'];
200       list($get, $post) = $this->finalize_params($method, $params);
201       $method_feed[] = $this->create_url_string(array_merge($post, $get));
202     }
203
204     $serial_only =
205       ($this->batch_mode == FacebookRestClient::BATCH_MODE_SERIAL_ONLY);
206
207     $params = array('method_feed' => json_encode($method_feed),
208                     'serial_only' => $serial_only,
209                     'format' => $this->format);
210     $result = $this->call_method('facebook.batch.run', $params);
211
212     if (is_array($result) && isset($result['error_code'])) {
213       throw new FacebookRestClientException($result['error_msg'],
214                                             $result['error_code']);
215     }
216
217     for ($i = 0; $i < $item_count; $i++) {
218       $batch_item = $this->batch_queue[$i];
219       $batch_item['p']['format'] = $this->format;
220       $batch_item_result = $this->convert_result($result[$i],
221                                                  $batch_item['m'],
222                                                  $batch_item['p']);
223
224       if (is_array($batch_item_result) &&
225           isset($batch_item_result['error_code'])) {
226         throw new FacebookRestClientException($batch_item_result['error_msg'],
227                                               $batch_item_result['error_code']);
228       }
229       $batch_item['r'] = $batch_item_result;
230     }
231   }
232
233   public function begin_permissions_mode($permissions_apikey) {
234     $this->call_as_apikey = $permissions_apikey;
235   }
236
237   public function end_permissions_mode() {
238     $this->call_as_apikey = '';
239   }
240
241
242   /*
243    * If a page is loaded via HTTPS, then all images and static
244    * resources need to be printed with HTTPS urls to avoid
245    * mixed content warnings. If your page loads with an HTTPS
246    * url, then call set_use_ssl_resources to retrieve the correct
247    * urls.
248    */
249   public function set_use_ssl_resources($is_ssl = true) {
250     $this->use_ssl_resources = $is_ssl;
251   }
252
253   /**
254    * Returns public information for an application (as shown in the application
255    * directory) by either application ID, API key, or canvas page name.
256    *
257    * @param int $application_id              (Optional) app id
258    * @param string $application_api_key      (Optional) api key
259    * @param string $application_canvas_name  (Optional) canvas name
260    *
261    * Exactly one argument must be specified, otherwise it is an error.
262    *
263    * @return array  An array of public information about the application.
264    */
265   public function application_getPublicInfo($application_id=null,
266                                             $application_api_key=null,
267                                             $application_canvas_name=null) {
268     return $this->call_method('facebook.application.getPublicInfo',
269         array('application_id' => $application_id,
270               'application_api_key' => $application_api_key,
271               'application_canvas_name' => $application_canvas_name));
272   }
273
274   /**
275    * Creates an authentication token to be used as part of the desktop login
276    * flow.  For more information, please see
277    * http://wiki.developers.facebook.com/index.php/Auth.createToken.
278    *
279    * @return string  An authentication token.
280    */
281   public function auth_createToken() {
282     return $this->call_method('facebook.auth.createToken');
283   }
284
285   /**
286    * Returns the session information available after current user logs in.
287    *
288    * @param string $auth_token the token returned by auth_createToken or
289    *               passed back to your callback_url.
290    * @param bool $generate_session_secret whether the session returned should
291    *             include a session secret
292    * @param string $host_url the connect site URL for which the session is
293    *               being generated.  This parameter is optional, unless
294    *               you want Facebook to determine which of several base domains
295    *               to choose from.  If this third argument isn't provided but
296    *               there are several base domains, the first base domain is
297    *               chosen.
298    *
299    * @return array  An assoc array containing session_key, uid
300    */
301   public function auth_getSession($auth_token,
302                                   $generate_session_secret = false,
303                                   $host_url = null) {
304     if (!$this->pending_batch()) {
305       $result = $this->call_method(
306         'facebook.auth.getSession',
307         array('auth_token' => $auth_token,
308               'generate_session_secret' => $generate_session_secret,
309               'host_url' => $host_url));
310       $this->session_key = $result['session_key'];
311
312       if (!empty($result['secret']) && !$generate_session_secret) {
313         // desktop apps have a special secret
314         $this->secret = $result['secret'];
315       }
316
317       return $result;
318     }
319   }
320
321   /**
322    * Generates a session-specific secret. This is for integration with
323    * client-side API calls, such as the JS library.
324    *
325    * @return array  A session secret for the current promoted session
326    *
327    * @error API_EC_PARAM_SESSION_KEY
328    *        API_EC_PARAM_UNKNOWN
329    */
330   public function auth_promoteSession() {
331       return $this->call_method('facebook.auth.promoteSession');
332   }
333
334   /**
335    * Expires the session that is currently being used.  If this call is
336    * successful, no further calls to the API (which require a session) can be
337    * made until a valid session is created.
338    *
339    * @return bool  true if session expiration was successful, false otherwise
340    */
341   public function auth_expireSession() {
342       return $this->call_method('facebook.auth.expireSession');
343   }
344
345   /**
346    *  Revokes the given extended permission that the user granted at some
347    *  prior time (for instance, offline_access or email).  If no user is
348    *  provided, it will be revoked for the user of the current session.
349    *
350    *  @param  string  $perm  The permission to revoke
351    *  @param  int     $uid   The user for whom to revoke the permission.
352    */
353   public function auth_revokeExtendedPermission($perm, $uid=null) {
354     return $this->call_method('facebook.auth.revokeExtendedPermission',
355         array('perm' => $perm, 'uid' => $uid));
356   }
357
358   /**
359    * Revokes the user's agreement to the Facebook Terms of Service for your
360    * application.  If you call this method for one of your users, you will no
361    * longer be able to make API requests on their behalf until they again
362    * authorize your application.  Use with care.  Note that if this method is
363    * called without a user parameter, then it will revoke access for the
364    * current session's user.
365    *
366    * @param int $uid  (Optional) User to revoke
367    *
368    * @return bool  true if revocation succeeds, false otherwise
369    */
370   public function auth_revokeAuthorization($uid=null) {
371       return $this->call_method('facebook.auth.revokeAuthorization',
372           array('uid' => $uid));
373   }
374
375   /**
376    * Get public key that is needed to verify digital signature
377    * an app may pass to other apps. The public key is only used by
378    * other apps for verification purposes.
379    * @param  string  API key of an app
380    * @return string  The public key for the app.
381    */
382   public function auth_getAppPublicKey($target_app_key) {
383     return $this->call_method('facebook.auth.getAppPublicKey',
384           array('target_app_key' => $target_app_key));
385   }
386
387   /**
388    * Get a structure that can be passed to another app
389    * as proof of session. The other app can verify it using public
390    * key of this app.
391    *
392    * @return signed public session data structure.
393    */
394   public function auth_getSignedPublicSessionData() {
395     return $this->call_method('facebook.auth.getSignedPublicSessionData',
396                               array());
397   }
398
399   /**
400    * Returns the number of unconnected friends that exist in this application.
401    * This number is determined based on the accounts registered through
402    * connect.registerUsers() (see below).
403    */
404   public function connect_getUnconnectedFriendsCount() {
405     return $this->call_method('facebook.connect.getUnconnectedFriendsCount',
406         array());
407   }
408
409  /**
410   * This method is used to create an association between an external user
411   * account and a Facebook user account, as per Facebook Connect.
412   *
413   * This method takes an array of account data, including a required email_hash
414   * and optional account data. For each connected account, if the user exists,
415   * the information is added to the set of the user's connected accounts.
416   * If the user has already authorized the site, the connected account is added
417   * in the confirmed state. If the user has not yet authorized the site, the
418   * connected account is added in the pending state.
419   *
420   * This is designed to help Facebook Connect recognize when two Facebook
421   * friends are both members of a external site, but perhaps are not aware of
422   * it.  The Connect dialog (see fb:connect-form) is used when friends can be
423   * identified through these email hashes. See the following url for details:
424   *
425   *   http://wiki.developers.facebook.com/index.php/Connect.registerUsers
426   *
427   * @param mixed $accounts A (JSON-encoded) array of arrays, where each array
428   *                        has three properties:
429   *                        'email_hash'  (req) - public email hash of account
430   *                        'account_id'  (opt) - remote account id;
431   *                        'account_url' (opt) - url to remote account;
432   *
433   * @return array  The list of email hashes for the successfully registered
434   *                accounts.
435   */
436   public function connect_registerUsers($accounts) {
437     return $this->call_method('facebook.connect.registerUsers',
438         array('accounts' => $accounts));
439   }
440
441  /**
442   * Unregisters a set of accounts registered using connect.registerUsers.
443   *
444   * @param array $email_hashes  The (JSON-encoded) list of email hashes to be
445   *                             unregistered.
446   *
447   * @return array  The list of email hashes which have been successfully
448   *                unregistered.
449   */
450   public function connect_unregisterUsers($email_hashes) {
451     return $this->call_method('facebook.connect.unregisterUsers',
452         array('email_hashes' => $email_hashes));
453   }
454
455   /**
456    * Returns events according to the filters specified.
457    *
458    * @param int $uid            (Optional) User associated with events. A null
459    *                            parameter will default to the session user.
460    * @param array/string $eids  (Optional) Filter by these event
461    *                            ids. A null parameter will get all events for
462    *                            the user. (A csv list will work but is deprecated)
463    * @param int $start_time     (Optional) Filter with this unix time as lower
464    *                            bound.  A null or zero parameter indicates no
465    *                            lower bound.
466    * @param int $end_time       (Optional) Filter with this UTC as upper bound.
467    *                            A null or zero parameter indicates no upper
468    *                            bound.
469    * @param string $rsvp_status (Optional) Only show events where the given uid
470    *                            has this rsvp status.  This only works if you
471    *                            have specified a value for $uid.  Values are as
472    *                            in events.getMembers.  Null indicates to ignore
473    *                            rsvp status when filtering.
474    *
475    * @return array  The events matching the query.
476    */
477   public function &events_get($uid=null,
478                               $eids=null,
479                               $start_time=null,
480                               $end_time=null,
481                               $rsvp_status=null) {
482     return $this->call_method('facebook.events.get',
483         array('uid' => $uid,
484               'eids' => $eids,
485               'start_time' => $start_time,
486               'end_time' => $end_time,
487               'rsvp_status' => $rsvp_status));
488   }
489
490   /**
491    * Returns membership list data associated with an event.
492    *
493    * @param int $eid  event id
494    *
495    * @return array  An assoc array of four membership lists, with keys
496    *                'attending', 'unsure', 'declined', and 'not_replied'
497    */
498   public function &events_getMembers($eid) {
499     return $this->call_method('facebook.events.getMembers',
500       array('eid' => $eid));
501   }
502
503   /**
504    * RSVPs the current user to this event.
505    *
506    * @param int $eid             event id
507    * @param string $rsvp_status  'attending', 'unsure', or 'declined'
508    *
509    * @return bool  true if successful
510    */
511   public function &events_rsvp($eid, $rsvp_status) {
512     return $this->call_method('facebook.events.rsvp',
513         array(
514         'eid' => $eid,
515         'rsvp_status' => $rsvp_status));
516   }
517
518   /**
519    * Cancels an event. Only works for events where application is the admin.
520    *
521    * @param int $eid                event id
522    * @param string $cancel_message  (Optional) message to send to members of
523    *                                the event about why it is cancelled
524    *
525    * @return bool  true if successful
526    */
527   public function &events_cancel($eid, $cancel_message='') {
528     return $this->call_method('facebook.events.cancel',
529         array('eid' => $eid,
530               'cancel_message' => $cancel_message));
531   }
532
533   /**
534    * Creates an event on behalf of the user is there is a session, otherwise on
535    * behalf of app.  Successful creation guarantees app will be admin.
536    *
537    * @param assoc array $event_info  json encoded event information
538    * @param string $file             (Optional) filename of picture to set
539    *
540    * @return int  event id
541    */
542   public function events_create($event_info, $file = null) {
543     if ($file) {
544       return $this->call_upload_method('facebook.events.create',
545         array('event_info' => $event_info),
546         $file,
547         $this->photo_server_addr);
548     } else {
549       return $this->call_method('facebook.events.create',
550         array('event_info' => $event_info));
551     }
552   }
553
554   /**
555    * Invites users to an event. If a session user exists, the session user
556    * must have permissions to invite friends to the event and $uids must contain
557    * a list of friend ids. Otherwise, the event must have been
558    * created by the app and $uids must contain users of the app.
559    * This method requires the 'create_event' extended permission to
560    * invite people on behalf of a user.
561    *
562    * @param $eid   the event id
563    * @param $uids  an array of users to invite
564    * @param $personal_message  a string containing the user's message
565    *                           (text only)
566    *
567    */
568   public function events_invite($eid, $uids, $personal_message) {
569     return $this->call_method('facebook.events.invite',
570                               array('eid' => $eid,
571                                     'uids' => $uids,
572                                     'personal_message' => $personal_message));
573   }
574
575   /**
576    * Edits an existing event. Only works for events where application is admin.
577    *
578    * @param int $eid                 event id
579    * @param assoc array $event_info  json encoded event information
580    * @param string $file             (Optional) filename of new picture to set
581    *
582    * @return bool  true if successful
583    */
584   public function events_edit($eid, $event_info, $file = null) {
585     if ($file) {
586       return $this->call_upload_method('facebook.events.edit',
587         array('eid' => $eid, 'event_info' => $event_info),
588         $file,
589         $this->photo_server_addr);
590     } else {
591       return $this->call_method('facebook.events.edit',
592         array('eid' => $eid,
593         'event_info' => $event_info));
594     }
595   }
596
597   /**
598    * Fetches and re-caches the image stored at the given URL, for use in images
599    * published to non-canvas pages via the API (for example, to user profiles
600    * via profile.setFBML, or to News Feed via feed.publishUserAction).
601    *
602    * @param string $url  The absolute URL from which to refresh the image.
603    *
604    * @return bool  true on success
605    */
606   public function &fbml_refreshImgSrc($url) {
607     return $this->call_method('facebook.fbml.refreshImgSrc',
608         array('url' => $url));
609   }
610
611   /**
612    * Fetches and re-caches the content stored at the given URL, for use in an
613    * fb:ref FBML tag.
614    *
615    * @param string $url  The absolute URL from which to fetch content. This URL
616    *                     should be used in a fb:ref FBML tag.
617    *
618    * @return bool  true on success
619    */
620   public function &fbml_refreshRefUrl($url) {
621     return $this->call_method('facebook.fbml.refreshRefUrl',
622         array('url' => $url));
623   }
624
625  /**
626    * Associates a given "handle" with FBML markup so that the handle can be
627    * used within the fb:ref FBML tag. A handle is unique within an application
628    * and allows an application to publish identical FBML to many user profiles
629    * and do subsequent updates without having to republish FBML on behalf of
630    * each user.
631    *
632    * @param string $handle  The handle to associate with the given FBML.
633    * @param string $fbml    The FBML to associate with the given handle.
634    *
635    * @return bool  true on success
636    */
637   public function &fbml_setRefHandle($handle, $fbml) {
638     return $this->call_method('facebook.fbml.setRefHandle',
639         array('handle' => $handle, 'fbml' => $fbml));
640   }
641
642   /**
643    * Register custom tags for the application. Custom tags can be used
644    * to extend the set of tags available to applications in FBML
645    * markup.
646    *
647    * Before you call this function,
648    * make sure you read the full documentation at
649    *
650    * http://wiki.developers.facebook.com/index.php/Fbml.RegisterCustomTags
651    *
652    * IMPORTANT: This function overwrites the values of
653    * existing tags if the names match. Use this function with care because
654    * it may break the FBML of any application that is using the
655    * existing version of the tags.
656    *
657    * @param mixed $tags an array of tag objects (the full description is on the
658    *   wiki page)
659    *
660    * @return int  the number of tags that were registered
661    */
662   public function &fbml_registerCustomTags($tags) {
663     $tags = json_encode($tags);
664     return $this->call_method('facebook.fbml.registerCustomTags',
665                               array('tags' => $tags));
666   }
667
668   /**
669    * Get the custom tags for an application. If $app_id
670    * is not specified, the calling app's tags are returned.
671    * If $app_id is different from the id of the calling app,
672    * only the app's public tags are returned.
673    * The return value is an array of the same type as
674    * the $tags parameter of fbml_registerCustomTags().
675    *
676    * @param int $app_id the application's id (optional)
677    *
678    * @return mixed  an array containing the custom tag  objects
679    */
680   public function &fbml_getCustomTags($app_id = null) {
681     return $this->call_method('facebook.fbml.getCustomTags',
682                               array('app_id' => $app_id));
683   }
684
685
686   /**
687    * Delete custom tags the application has registered. If
688    * $tag_names is null, all the application's custom tags will be
689    * deleted.
690    *
691    * IMPORTANT: If your application has registered public tags
692    * that other applications may be using, don't delete those tags!
693    * Doing so can break the FBML ofapplications that are using them.
694    *
695    * @param array $tag_names the names of the tags to delete (optinal)
696    * @return bool true on success
697    */
698   public function &fbml_deleteCustomTags($tag_names = null) {
699     return $this->call_method('facebook.fbml.deleteCustomTags',
700                               array('tag_names' => json_encode($tag_names)));
701   }
702
703   /**
704    * Gets the best translations for native strings submitted by an application
705    * for translation. If $locale is not specified, only native strings and their
706    * descriptions are returned. If $all is true, then unapproved translations
707    * are returned as well, otherwise only approved translations are returned.
708    *
709    * A mapping of locale codes -> language names is available at
710    * http://wiki.developers.facebook.com/index.php/Facebook_Locales
711    *
712    * @param string $locale the locale to get translations for, or 'all' for all
713    *                       locales, or 'en_US' for native strings
714    * @param bool   $all    whether to return all or only approved translations
715    *
716    * @return array (locale, array(native_strings, array('best translation
717    *                available given enough votes or manual approval', approval
718    *                                                                  status)))
719    * @error API_EC_PARAM
720    * @error API_EC_PARAM_BAD_LOCALE
721    */
722   public function &intl_getTranslations($locale = 'en_US', $all = false) {
723     return $this->call_method('facebook.intl.getTranslations',
724                               array('locale' => $locale,
725                                     'all'    => $all));
726   }
727
728   /**
729    * Lets you insert text strings in their native language into the Facebook
730    * Translations database so they can be translated.
731    *
732    * @param array $native_strings  An array of maps, where each map has a 'text'
733    *                               field and a 'description' field.
734    *
735    * @return int  Number of strings uploaded.
736    */
737   public function &intl_uploadNativeStrings($native_strings) {
738     return $this->call_method('facebook.intl.uploadNativeStrings',
739         array('native_strings' => json_encode($native_strings)));
740   }
741
742   /**
743    * This method is deprecated for calls made on behalf of users. This method
744    * works only for publishing stories on a Facebook Page that has installed
745    * your application. To publish stories to a user's profile, use
746    * feed.publishUserAction instead.
747    *
748    * For more details on this call, please visit the wiki page:
749    *
750    * http://wiki.developers.facebook.com/index.php/Feed.publishTemplatizedAction
751    */
752   public function &feed_publishTemplatizedAction($title_template,
753                                                  $title_data,
754                                                  $body_template,
755                                                  $body_data,
756                                                  $body_general,
757                                                  $image_1=null,
758                                                  $image_1_link=null,
759                                                  $image_2=null,
760                                                  $image_2_link=null,
761                                                  $image_3=null,
762                                                  $image_3_link=null,
763                                                  $image_4=null,
764                                                  $image_4_link=null,
765                                                  $target_ids='',
766                                                  $page_actor_id=null) {
767     return $this->call_method('facebook.feed.publishTemplatizedAction',
768       array('title_template' => $title_template,
769             'title_data' => $title_data,
770             'body_template' => $body_template,
771             'body_data' => $body_data,
772             'body_general' => $body_general,
773             'image_1' => $image_1,
774             'image_1_link' => $image_1_link,
775             'image_2' => $image_2,
776             'image_2_link' => $image_2_link,
777             'image_3' => $image_3,
778             'image_3_link' => $image_3_link,
779             'image_4' => $image_4,
780             'image_4_link' => $image_4_link,
781             'target_ids' => $target_ids,
782             'page_actor_id' => $page_actor_id));
783   }
784
785   /**
786    * Registers a template bundle.  Template bundles are somewhat involved, so
787    * it's recommended you check out the wiki for more details:
788    *
789    *  http://wiki.developers.facebook.com/index.php/Feed.registerTemplateBundle
790    *
791    * @return string  A template bundle id
792    */
793   public function &feed_registerTemplateBundle($one_line_story_templates,
794                                                $short_story_templates = array(),
795                                                $full_story_template = null,
796                                                $action_links = array()) {
797
798     $one_line_story_templates = json_encode($one_line_story_templates);
799
800     if (!empty($short_story_templates)) {
801       $short_story_templates = json_encode($short_story_templates);
802     }
803
804     if (isset($full_story_template)) {
805       $full_story_template = json_encode($full_story_template);
806     }
807
808     if (isset($action_links)) {
809       $action_links = json_encode($action_links);
810     }
811
812     return $this->call_method('facebook.feed.registerTemplateBundle',
813         array('one_line_story_templates' => $one_line_story_templates,
814               'short_story_templates' => $short_story_templates,
815               'full_story_template' => $full_story_template,
816               'action_links' => $action_links));
817   }
818
819   /**
820    * Retrieves the full list of active template bundles registered by the
821    * requesting application.
822    *
823    * @return array  An array of template bundles
824    */
825   public function &feed_getRegisteredTemplateBundles() {
826     return $this->call_method('facebook.feed.getRegisteredTemplateBundles',
827         array());
828   }
829
830   /**
831    * Retrieves information about a specified template bundle previously
832    * registered by the requesting application.
833    *
834    * @param string $template_bundle_id  The template bundle id
835    *
836    * @return array  Template bundle
837    */
838   public function &feed_getRegisteredTemplateBundleByID($template_bundle_id) {
839     return $this->call_method('facebook.feed.getRegisteredTemplateBundleByID',
840         array('template_bundle_id' => $template_bundle_id));
841   }
842
843   /**
844    * Deactivates a previously registered template bundle.
845    *
846    * @param string $template_bundle_id  The template bundle id
847    *
848    * @return bool  true on success
849    */
850   public function &feed_deactivateTemplateBundleByID($template_bundle_id) {
851     return $this->call_method('facebook.feed.deactivateTemplateBundleByID',
852         array('template_bundle_id' => $template_bundle_id));
853   }
854
855   const STORY_SIZE_ONE_LINE = 1;
856   const STORY_SIZE_SHORT = 2;
857   const STORY_SIZE_FULL = 4;
858
859   /**
860    * Publishes a story on behalf of the user owning the session, using the
861    * specified template bundle. This method requires an active session key in
862    * order to be called.
863    *
864    * The parameters to this method ($templata_data in particular) are somewhat
865    * involved.  It's recommended you visit the wiki for details:
866    *
867    *  http://wiki.developers.facebook.com/index.php/Feed.publishUserAction
868    *
869    * @param int $template_bundle_id  A template bundle id previously registered
870    * @param array $template_data     See wiki article for syntax
871    * @param array $target_ids        (Optional) An array of friend uids of the
872    *                                 user who shared in this action.
873    * @param string $body_general     (Optional) Additional markup that extends
874    *                                 the body of a short story.
875    * @param int $story_size          (Optional) A story size (see above)
876    * @param string $user_message     (Optional) A user message for a short
877    *                                 story.
878    *
879    * @return bool  true on success
880    */
881   public function &feed_publishUserAction(
882       $template_bundle_id, $template_data, $target_ids='', $body_general='',
883       $story_size=FacebookRestClient::STORY_SIZE_ONE_LINE,
884       $user_message='') {
885
886     if (is_array($template_data)) {
887       $template_data = json_encode($template_data);
888     } // allow client to either pass in JSON or an assoc that we JSON for them
889
890     if (is_array($target_ids)) {
891       $target_ids = json_encode($target_ids);
892       $target_ids = trim($target_ids, "[]"); // we don't want square brackets
893     }
894
895     return $this->call_method('facebook.feed.publishUserAction',
896         array('template_bundle_id' => $template_bundle_id,
897               'template_data' => $template_data,
898               'target_ids' => $target_ids,
899               'body_general' => $body_general,
900               'story_size' => $story_size,
901               'user_message' => $user_message));
902   }
903
904
905   /**
906    * Publish a post to the user's stream.
907    *
908    * @param $message        the user's message
909    * @param $attachment     the post's attachment (optional)
910    * @param $action links   the post's action links (optional)
911    * @param $target_id      the user on whose wall the post will be posted
912    *                        (optional)
913    * @param $uid            the actor (defaults to session user)
914    * @return string the post id
915    */
916   public function stream_publish(
917     $message, $attachment = null, $action_links = null, $target_id = null,
918     $uid = null) {
919
920     return $this->call_method(
921       'facebook.stream.publish',
922       array('message' => $message,
923             'attachment' => $attachment,
924             'action_links' => $action_links,
925             'target_id' => $target_id,
926             'uid' => $this->get_uid($uid)));
927   }
928
929   /**
930    * Remove a post from the user's stream.
931    * Currently, you may only remove stories you application created.
932    *
933    * @param $post_id  the post id
934    * @param $uid      the actor (defaults to session user)
935    * @return bool
936    */
937   public function stream_remove($post_id, $uid = null) {
938     return $this->call_method(
939       'facebook.stream.remove',
940       array('post_id' => $post_id,
941             'uid' => $this->get_uid($uid)));
942   }
943
944   /**
945    * Add a comment to a stream post
946    *
947    * @param $post_id  the post id
948    * @param $comment  the comment text
949    * @param $uid      the actor (defaults to session user)
950    * @return string the id of the created comment
951    */
952   public function stream_addComment($post_id, $comment, $uid = null) {
953     return $this->call_method(
954       'facebook.stream.addComment',
955       array('post_id' => $post_id,
956             'comment' => $comment,
957             'uid' => $this->get_uid($uid)));
958   }
959
960
961   /**
962    * Remove a comment from a stream post
963    *
964    * @param $comment_id  the comment id
965    * @param $uid      the actor (defaults to session user)
966    * @return bool
967    */
968   public function stream_removeComment($comment_id, $uid = null) {
969     return $this->call_method(
970       'facebook.stream.removeComment',
971       array('comment_id' => $comment_id,
972             'uid' => $this->get_uid($uid)));
973   }
974
975   /**
976    * Add a like to a stream post
977    *
978    * @param $post_id  the post id
979    * @param $uid      the actor (defaults to session user)
980    * @return bool
981    */
982   public function stream_addLike($post_id, $uid = null) {
983     return $this->call_method(
984       'facebook.stream.addLike',
985       array('post_id' => $post_id,
986             'uid' => $this->get_uid($uid)));
987   }
988
989   /**
990    * Remove a like from a stream post
991    *
992    * @param $post_id  the post id
993    * @param $uid      the actor (defaults to session user)
994    * @return bool
995    */
996   public function stream_removeLike($post_id, $uid = null) {
997     return $this->call_method(
998       'facebook.stream.removeLike',
999       array('post_id' => $post_id,
1000             'uid' => $this->get_uid($uid)));
1001   }
1002
1003   /**
1004    * For the current user, retrieves stories generated by the user's friends
1005    * while using this application.  This can be used to easily create a
1006    * "News Feed" like experience.
1007    *
1008    * @return array  An array of feed story objects.
1009    */
1010   public function &feed_getAppFriendStories() {
1011     return $this->call_method('facebook.feed.getAppFriendStories');
1012   }
1013
1014   /**
1015    * Makes an FQL query.  This is a generalized way of accessing all the data
1016    * in the API, as an alternative to most of the other method calls.  More
1017    * info at http://wiki.developers.facebook.com/index.php/FQL
1018    *
1019    * @param string $query  the query to evaluate
1020    *
1021    * @return array  generalized array representing the results
1022    */
1023   public function &fql_query($query) {
1024     return $this->call_method('facebook.fql.query',
1025       array('query' => $query));
1026   }
1027
1028   /**
1029    * Makes a set of FQL queries in parallel.  This method takes a dictionary
1030    * of FQL queries where the keys are names for the queries.  Results from
1031    * one query can be used within another query to fetch additional data.  More
1032    * info about FQL queries at http://wiki.developers.facebook.com/index.php/FQL
1033    *
1034    * @param string $queries  JSON-encoded dictionary of queries to evaluate
1035    *
1036    * @return array  generalized array representing the results
1037    */
1038   public function &fql_multiquery($queries) {
1039     return $this->call_method('facebook.fql.multiquery',
1040       array('queries' => $queries));
1041   }
1042
1043   /**
1044    * Returns whether or not pairs of users are friends.
1045    * Note that the Facebook friend relationship is symmetric.
1046    *
1047    * @param array/string $uids1  list of ids (id_1, id_2,...)
1048    *                       of some length X (csv is deprecated)
1049    * @param array/string $uids2  list of ids (id_A, id_B,...)
1050    *                       of SAME length X (csv is deprecated)
1051    *
1052    * @return array  An array with uid1, uid2, and bool if friends, e.g.:
1053    *   array(0 => array('uid1' => id_1, 'uid2' => id_A, 'are_friends' => 1),
1054    *         1 => array('uid1' => id_2, 'uid2' => id_B, 'are_friends' => 0)
1055    *         ...)
1056    * @error
1057    *    API_EC_PARAM_USER_ID_LIST
1058    */
1059   public function &friends_areFriends($uids1, $uids2) {
1060     return $this->call_method('facebook.friends.areFriends',
1061                  array('uids1' => $uids1,
1062                        'uids2' => $uids2));
1063   }
1064
1065   /**
1066    * Returns the friends of the current session user.
1067    *
1068    * @param int $flid  (Optional) Only return friends on this friend list.
1069    * @param int $uid   (Optional) Return friends for this user.
1070    *
1071    * @return array  An array of friends
1072    */
1073   public function &friends_get($flid=null, $uid = null) {
1074     if (isset($this->friends_list)) {
1075       return $this->friends_list;
1076     }
1077     $params = array();
1078     if (!$uid && isset($this->canvas_user)) {
1079       $uid = $this->canvas_user;
1080     }
1081     if ($uid) {
1082       $params['uid'] = $uid;
1083     }
1084     if ($flid) {
1085       $params['flid'] = $flid;
1086     }
1087     return $this->call_method('facebook.friends.get', $params);
1088
1089   }
1090
1091   /**
1092    * Returns the mutual friends between the target uid and a source uid or
1093    * the current session user.
1094    *
1095    * @param int $target_uid Target uid for which mutual friends will be found.
1096    * @param int $source_uid (optional) Source uid for which mutual friends will
1097    *                                   be found. If no source_uid is specified,
1098    *                                   source_id will default to the session
1099    *                                   user.
1100    * @return array  An array of friend uids
1101    */
1102   public function &friends_getMutualFriends($target_uid, $source_uid = null) {
1103     return $this->call_method('facebook.friends.getMutualFriends',
1104                               array("target_uid" => $target_uid,
1105                                     "source_uid" => $source_uid));
1106   }
1107
1108   /**
1109    * Returns the set of friend lists for the current session user.
1110    *
1111    * @return array  An array of friend list objects
1112    */
1113   public function &friends_getLists() {
1114     return $this->call_method('facebook.friends.getLists');
1115   }
1116
1117   /**
1118    * Returns the friends of the session user, who are also users
1119    * of the calling application.
1120    *
1121    * @return array  An array of friends also using the app
1122    */
1123   public function &friends_getAppUsers() {
1124     return $this->call_method('facebook.friends.getAppUsers');
1125   }
1126
1127   /**
1128    * Returns groups according to the filters specified.
1129    *
1130    * @param int $uid     (Optional) User associated with groups.  A null
1131    *                     parameter will default to the session user.
1132    * @param array/string $gids (Optional) Array of group ids to query. A null
1133    *                     parameter will get all groups for the user.
1134    *                     (csv is deprecated)
1135    *
1136    * @return array  An array of group objects
1137    */
1138   public function &groups_get($uid, $gids) {
1139     return $this->call_method('facebook.groups.get',
1140         array('uid' => $uid,
1141               'gids' => $gids));
1142   }
1143
1144   /**
1145    * Returns the membership list of a group.
1146    *
1147    * @param int $gid  Group id
1148    *
1149    * @return array  An array with four membership lists, with keys 'members',
1150    *                'admins', 'officers', and 'not_replied'
1151    */
1152   public function &groups_getMembers($gid) {
1153     return $this->call_method('facebook.groups.getMembers',
1154       array('gid' => $gid));
1155   }
1156
1157   /**
1158    * Returns cookies according to the filters specified.
1159    *
1160    * @param int $uid     User for which the cookies are needed.
1161    * @param string $name (Optional) A null parameter will get all cookies
1162    *                     for the user.
1163    *
1164    * @return array  Cookies!  Nom nom nom nom nom.
1165    */
1166   public function data_getCookies($uid, $name) {
1167     return $this->call_method('facebook.data.getCookies',
1168         array('uid' => $uid,
1169               'name' => $name));
1170   }
1171
1172   /**
1173    * Sets cookies according to the params specified.
1174    *
1175    * @param int $uid       User for which the cookies are needed.
1176    * @param string $name   Name of the cookie
1177    * @param string $value  (Optional) if expires specified and is in the past
1178    * @param int $expires   (Optional) Expiry time
1179    * @param string $path   (Optional) Url path to associate with (default is /)
1180    *
1181    * @return bool  true on success
1182    */
1183   public function data_setCookie($uid, $name, $value, $expires, $path) {
1184     return $this->call_method('facebook.data.setCookie',
1185         array('uid' => $uid,
1186               'name' => $name,
1187               'value' => $value,
1188               'expires' => $expires,
1189               'path' => $path));
1190   }
1191
1192   /**
1193    * Retrieves links posted by the given user.
1194    *
1195    * @param int    $uid      The user whose links you wish to retrieve
1196    * @param int    $limit    The maximimum number of links to retrieve
1197    * @param array $link_ids (Optional) Array of specific link
1198    *                          IDs to retrieve by this user
1199    *
1200    * @return array  An array of links.
1201    */
1202   public function &links_get($uid, $limit, $link_ids = null) {
1203     return $this->call_method('links.get',
1204         array('uid' => $uid,
1205               'limit' => $limit,
1206               'link_ids' => $link_ids));
1207   }
1208
1209   /**
1210    * Posts a link on Facebook.
1211    *
1212    * @param string $url     URL/link you wish to post
1213    * @param string $comment (Optional) A comment about this link
1214    * @param int    $uid     (Optional) User ID that is posting this link;
1215    *                        defaults to current session user
1216    *
1217    * @return bool
1218    */
1219   public function &links_post($url, $comment='', $uid = null) {
1220     return $this->call_method('links.post',
1221         array('uid' => $uid,
1222               'url' => $url,
1223               'comment' => $comment));
1224   }
1225
1226   /**
1227    * Permissions API
1228    */
1229
1230   /**
1231    * Checks API-access granted by self to the specified application.
1232    *
1233    * @param string $permissions_apikey  Other application key
1234    *
1235    * @return array  API methods/namespaces which are allowed access
1236    */
1237   public function permissions_checkGrantedApiAccess($permissions_apikey) {
1238     return $this->call_method('facebook.permissions.checkGrantedApiAccess',
1239         array('permissions_apikey' => $permissions_apikey));
1240   }
1241
1242   /**
1243    * Checks API-access granted to self by the specified application.
1244    *
1245    * @param string $permissions_apikey  Other application key
1246    *
1247    * @return array  API methods/namespaces which are allowed access
1248    */
1249   public function permissions_checkAvailableApiAccess($permissions_apikey) {
1250     return $this->call_method('facebook.permissions.checkAvailableApiAccess',
1251         array('permissions_apikey' => $permissions_apikey));
1252   }
1253
1254   /**
1255    * Grant API-access to the specified methods/namespaces to the specified
1256    * application.
1257    *
1258    * @param string $permissions_apikey  Other application key
1259    * @param array(string) $method_arr   (Optional) API methods/namespaces
1260    *                                    allowed
1261    *
1262    * @return array  API methods/namespaces which are allowed access
1263    */
1264   public function permissions_grantApiAccess($permissions_apikey, $method_arr) {
1265     return $this->call_method('facebook.permissions.grantApiAccess',
1266         array('permissions_apikey' => $permissions_apikey,
1267               'method_arr' => $method_arr));
1268   }
1269
1270   /**
1271    * Revoke API-access granted to the specified application.
1272    *
1273    * @param string $permissions_apikey  Other application key
1274    *
1275    * @return bool  true on success
1276    */
1277   public function permissions_revokeApiAccess($permissions_apikey) {
1278     return $this->call_method('facebook.permissions.revokeApiAccess',
1279         array('permissions_apikey' => $permissions_apikey));
1280   }
1281
1282   /**
1283    * Payments Order API
1284    */
1285
1286   /**
1287    * Set Payments properties for an app.
1288    *
1289    * @param  properties  a map from property names to  values
1290    * @return             true on success
1291    */
1292   public function payments_setProperties($properties) {
1293     return $this->call_method ('facebook.payments.setProperties',
1294         array('properties' => json_encode($properties)));
1295   }
1296
1297   public function payments_getOrderDetails($order_id) {
1298     return json_decode($this->call_method(
1299         'facebook.payments.getOrderDetails',
1300         array('order_id' => $order_id)), true);
1301   }
1302
1303   public function payments_updateOrder($order_id, $status,
1304                                          $params) {
1305     return $this->call_method('facebook.payments.updateOrder',
1306         array('order_id' => $order_id,
1307               'status' => $status,
1308               'params' => json_encode($params)));
1309   }
1310
1311   public function payments_getOrders($status, $start_time,
1312                                        $end_time, $test_mode=false) {
1313     return json_decode($this->call_method('facebook.payments.getOrders',
1314         array('status' => $status,
1315               'start_time' => $start_time,
1316               'end_time' => $end_time,
1317               'test_mode' => $test_mode)), true);
1318   }
1319
1320   /**
1321    * Gifts API
1322    */
1323
1324   /**
1325    * Get Gifts associated with an app
1326    *
1327    * @return             array of gifts
1328    */
1329   public function gifts_get() {
1330     return json_decode(
1331         $this->call_method('facebook.gifts.get',
1332                            array()),
1333         true
1334         );
1335   }
1336
1337   /*
1338    * Update gifts stored by an app
1339    *
1340    * @param array containing gift_id => gift_data to be updated
1341    * @return array containing gift_id => true/false indicating success
1342    *                                     in updating that gift
1343    */
1344   public function gifts_update($update_array) {
1345     return json_decode(
1346       $this->call_method('facebook.gifts.update',
1347                          array('update_str' => json_encode($update_array))
1348                         ),
1349       true
1350     );
1351   }
1352
1353
1354   /**
1355    * Creates a note with the specified title and content.
1356    *
1357    * @param string $title   Title of the note.
1358    * @param string $content Content of the note.
1359    * @param int    $uid     (Optional) The user for whom you are creating a
1360    *                        note; defaults to current session user
1361    *
1362    * @return int   The ID of the note that was just created.
1363    */
1364   public function &notes_create($title, $content, $uid = null) {
1365     return $this->call_method('notes.create',
1366         array('uid' => $uid,
1367               'title' => $title,
1368               'content' => $content));
1369   }
1370
1371   /**
1372    * Deletes the specified note.
1373    *
1374    * @param int $note_id  ID of the note you wish to delete
1375    * @param int $uid      (Optional) Owner of the note you wish to delete;
1376    *                      defaults to current session user
1377    *
1378    * @return bool
1379    */
1380   public function &notes_delete($note_id, $uid = null) {
1381     return $this->call_method('notes.delete',
1382         array('uid' => $uid,
1383               'note_id' => $note_id));
1384   }
1385
1386   /**
1387    * Edits a note, replacing its title and contents with the title
1388    * and contents specified.
1389    *
1390    * @param int    $note_id  ID of the note you wish to edit
1391    * @param string $title    Replacement title for the note
1392    * @param string $content  Replacement content for the note
1393    * @param int    $uid      (Optional) Owner of the note you wish to edit;
1394    *                         defaults to current session user
1395    *
1396    * @return bool
1397    */
1398   public function &notes_edit($note_id, $title, $content, $uid = null) {
1399     return $this->call_method('notes.edit',
1400         array('uid' => $uid,
1401               'note_id' => $note_id,
1402               'title' => $title,
1403               'content' => $content));
1404   }
1405
1406   /**
1407    * Retrieves all notes by a user. If note_ids are specified,
1408    * retrieves only those specific notes by that user.
1409    *
1410    * @param int    $uid      User whose notes you wish to retrieve
1411    * @param array  $note_ids (Optional) List of specific note
1412    *                         IDs by this user to retrieve
1413    *
1414    * @return array A list of all of the given user's notes, or an empty list
1415    *               if the viewer lacks permissions or if there are no visible
1416    *               notes.
1417    */
1418   public function &notes_get($uid, $note_ids = null) {
1419     return $this->call_method('notes.get',
1420         array('uid' => $uid,
1421               'note_ids' => $note_ids));
1422   }
1423
1424
1425   /**
1426    * Returns the outstanding notifications for the session user.
1427    *
1428    * @return array An assoc array of notification count objects for
1429    *               'messages', 'pokes' and 'shares', a uid list of
1430    *               'friend_requests', a gid list of 'group_invites',
1431    *               and an eid list of 'event_invites'
1432    */
1433   public function &notifications_get() {
1434     return $this->call_method('facebook.notifications.get');
1435   }
1436
1437   /**
1438    * Sends a notification to the specified users.
1439    *
1440    * @return A comma separated list of successful recipients
1441    * @error
1442    *    API_EC_PARAM_USER_ID_LIST
1443    */
1444   public function &notifications_send($to_ids, $notification, $type) {
1445     return $this->call_method('facebook.notifications.send',
1446         array('to_ids' => $to_ids,
1447               'notification' => $notification,
1448               'type' => $type));
1449   }
1450
1451   /**
1452    * Sends an email to the specified user of the application.
1453    *
1454    * @param array/string $recipients array of ids of the recipients (csv is deprecated)
1455    * @param string $subject    subject of the email
1456    * @param string $text       (plain text) body of the email
1457    * @param string $fbml       fbml markup for an html version of the email
1458    *
1459    * @return string  A comma separated list of successful recipients
1460    * @error
1461    *    API_EC_PARAM_USER_ID_LIST
1462    */
1463   public function &notifications_sendEmail($recipients,
1464                                            $subject,
1465                                            $text,
1466                                            $fbml) {
1467     return $this->call_method('facebook.notifications.sendEmail',
1468         array('recipients' => $recipients,
1469               'subject' => $subject,
1470               'text' => $text,
1471               'fbml' => $fbml));
1472   }
1473
1474   /**
1475    * Returns the requested info fields for the requested set of pages.
1476    *
1477    * @param array/string $page_ids  an array of page ids (csv is deprecated)
1478    * @param array/string  $fields    an array of strings describing the
1479    *                           info fields desired (csv is deprecated)
1480    * @param int    $uid       (Optional) limit results to pages of which this
1481    *                          user is a fan.
1482    * @param string type       limits results to a particular type of page.
1483    *
1484    * @return array  An array of pages
1485    */
1486   public function &pages_getInfo($page_ids, $fields, $uid, $type) {
1487     return $this->call_method('facebook.pages.getInfo',
1488         array('page_ids' => $page_ids,
1489               'fields' => $fields,
1490               'uid' => $uid,
1491               'type' => $type));
1492   }
1493
1494   /**
1495    * Returns true if the given user is an admin for the passed page.
1496    *
1497    * @param int $page_id  target page id
1498    * @param int $uid      (Optional) user id (defaults to the logged-in user)
1499    *
1500    * @return bool  true on success
1501    */
1502   public function &pages_isAdmin($page_id, $uid = null) {
1503     return $this->call_method('facebook.pages.isAdmin',
1504         array('page_id' => $page_id,
1505               'uid' => $uid));
1506   }
1507
1508   /**
1509    * Returns whether or not the given page has added the application.
1510    *
1511    * @param int $page_id  target page id
1512    *
1513    * @return bool  true on success
1514    */
1515   public function &pages_isAppAdded($page_id) {
1516     return $this->call_method('facebook.pages.isAppAdded',
1517         array('page_id' => $page_id));
1518   }
1519
1520   /**
1521    * Returns true if logged in user is a fan for the passed page.
1522    *
1523    * @param int $page_id target page id
1524    * @param int $uid user to compare.  If empty, the logged in user.
1525    *
1526    * @return bool  true on success
1527    */
1528   public function &pages_isFan($page_id, $uid = null) {
1529     return $this->call_method('facebook.pages.isFan',
1530         array('page_id' => $page_id,
1531               'uid' => $uid));
1532   }
1533
1534   /**
1535    * Adds a tag with the given information to a photo. See the wiki for details:
1536    *
1537    *  http://wiki.developers.facebook.com/index.php/Photos.addTag
1538    *
1539    * @param int $pid          The ID of the photo to be tagged
1540    * @param int $tag_uid      The ID of the user being tagged. You must specify
1541    *                          either the $tag_uid or the $tag_text parameter
1542    *                          (unless $tags is specified).
1543    * @param string $tag_text  Some text identifying the person being tagged.
1544    *                          You must specify either the $tag_uid or $tag_text
1545    *                          parameter (unless $tags is specified).
1546    * @param float $x          The horizontal position of the tag, as a
1547    *                          percentage from 0 to 100, from the left of the
1548    *                          photo.
1549    * @param float $y          The vertical position of the tag, as a percentage
1550    *                          from 0 to 100, from the top of the photo.
1551    * @param array $tags       (Optional) An array of maps, where each map
1552    *                          can contain the tag_uid, tag_text, x, and y
1553    *                          parameters defined above.  If specified, the
1554    *                          individual arguments are ignored.
1555    * @param int $owner_uid    (Optional)  The user ID of the user whose photo
1556    *                          you are tagging. If this parameter is not
1557    *                          specified, then it defaults to the session user.
1558    *
1559    * @return bool  true on success
1560    */
1561   public function &photos_addTag($pid,
1562                                  $tag_uid,
1563                                  $tag_text,
1564                                  $x,
1565                                  $y,
1566                                  $tags,
1567                                  $owner_uid=0) {
1568     return $this->call_method('facebook.photos.addTag',
1569         array('pid' => $pid,
1570               'tag_uid' => $tag_uid,
1571               'tag_text' => $tag_text,
1572               'x' => $x,
1573               'y' => $y,
1574               'tags' => (is_array($tags)) ? json_encode($tags) : null,
1575               'owner_uid' => $this->get_uid($owner_uid)));
1576   }
1577
1578   /**
1579    * Creates and returns a new album owned by the specified user or the current
1580    * session user.
1581    *
1582    * @param string $name         The name of the album.
1583    * @param string $description  (Optional) A description of the album.
1584    * @param string $location     (Optional) A description of the location.
1585    * @param string $visible      (Optional) A privacy setting for the album.
1586    *                             One of 'friends', 'friends-of-friends',
1587    *                             'networks', or 'everyone'.  Default 'everyone'.
1588    * @param int $uid             (Optional) User id for creating the album; if
1589    *                             not specified, the session user is used.
1590    *
1591    * @return array  An album object
1592    */
1593   public function &photos_createAlbum($name,
1594                                       $description='',
1595                                       $location='',
1596                                       $visible='',
1597                                       $uid=0) {
1598     return $this->call_method('facebook.photos.createAlbum',
1599         array('name' => $name,
1600               'description' => $description,
1601               'location' => $location,
1602               'visible' => $visible,
1603               'uid' => $this->get_uid($uid)));
1604   }
1605
1606   /**
1607    * Returns photos according to the filters specified.
1608    *
1609    * @param int $subj_id  (Optional) Filter by uid of user tagged in the photos.
1610    * @param int $aid      (Optional) Filter by an album, as returned by
1611    *                      photos_getAlbums.
1612    * @param array/string $pids   (Optional) Restrict to an array of pids
1613    *                             (csv is deprecated)
1614    *
1615    * Note that at least one of these parameters needs to be specified, or an
1616    * error is returned.
1617    *
1618    * @return array  An array of photo objects.
1619    */
1620   public function &photos_get($subj_id, $aid, $pids) {
1621     return $this->call_method('facebook.photos.get',
1622       array('subj_id' => $subj_id, 'aid' => $aid, 'pids' => $pids));
1623   }
1624
1625   /**
1626    * Returns the albums created by the given user.
1627    *
1628    * @param int $uid      (Optional) The uid of the user whose albums you want.
1629    *                       A null will return the albums of the session user.
1630    * @param string $aids  (Optional) An array of aids to restrict
1631    *                       the query. (csv is deprecated)
1632    *
1633    * Note that at least one of the (uid, aids) parameters must be specified.
1634    *
1635    * @returns an array of album objects.
1636    */
1637   public function &photos_getAlbums($uid, $aids) {
1638     return $this->call_method('facebook.photos.getAlbums',
1639       array('uid' => $uid,
1640             'aids' => $aids));
1641   }
1642
1643   /**
1644    * Returns the tags on all photos specified.
1645    *
1646    * @param string $pids  A list of pids to query
1647    *
1648    * @return array  An array of photo tag objects, which include pid,
1649    *                subject uid, and two floating-point numbers (xcoord, ycoord)
1650    *                for tag pixel location.
1651    */
1652   public function &photos_getTags($pids) {
1653     return $this->call_method('facebook.photos.getTags',
1654       array('pids' => $pids));
1655   }
1656
1657   /**
1658    * Uploads a photo.
1659    *
1660    * @param string $file     The location of the photo on the local filesystem.
1661    * @param int $aid         (Optional) The album into which to upload the
1662    *                         photo.
1663    * @param string $caption  (Optional) A caption for the photo.
1664    * @param int uid          (Optional) The user ID of the user whose photo you
1665    *                         are uploading
1666    *
1667    * @return array  An array of user objects
1668    */
1669   public function photos_upload($file, $aid=null, $caption=null, $uid=null) {
1670     return $this->call_upload_method('facebook.photos.upload',
1671                                      array('aid' => $aid,
1672                                            'caption' => $caption,
1673                                            'uid' => $uid),
1674                                      $file);
1675   }
1676
1677
1678   /**
1679    * Uploads a video.
1680    *
1681    * @param  string $file        The location of the video on the local filesystem.
1682    * @param  string $title       (Optional) A title for the video. Titles over 65 characters in length will be truncated.
1683    * @param  string $description (Optional) A description for the video.
1684    *
1685    * @return array  An array with the video's ID, title, description, and a link to view it on Facebook.
1686    */
1687   public function video_upload($file, $title=null, $description=null) {
1688     return $this->call_upload_method('facebook.video.upload',
1689                                      array('title' => $title,
1690                                            'description' => $description),
1691                                      $file,
1692                                      Facebook::get_facebook_url('api-video') . '/restserver.php');
1693   }
1694
1695   /**
1696    * Returns an array with the video limitations imposed on the current session's
1697    * associated user. Maximum length is measured in seconds; maximum size is
1698    * measured in bytes.
1699    *
1700    * @return array  Array with "length" and "size" keys
1701    */
1702   public function &video_getUploadLimits() {
1703     return $this->call_method('facebook.video.getUploadLimits');
1704   }
1705
1706   /**
1707    * Returns the requested info fields for the requested set of users.
1708    *
1709    * @param array/string $uids    An array of user ids (csv is deprecated)
1710    * @param array/string $fields  An array of info field names desired (csv is deprecated)
1711    *
1712    * @return array  An array of user objects
1713    */
1714   public function &users_getInfo($uids, $fields) {
1715     return $this->call_method('facebook.users.getInfo',
1716                   array('uids' => $uids,
1717                         'fields' => $fields));
1718   }
1719
1720   /**
1721    * Returns the requested info fields for the requested set of users. A
1722    * session key must not be specified. Only data about users that have
1723    * authorized your application will be returned.
1724    *
1725    * Check the wiki for fields that can be queried through this API call.
1726    * Data returned from here should not be used for rendering to application
1727    * users, use users.getInfo instead, so that proper privacy rules will be
1728    * applied.
1729    *
1730    * @param array/string $uids    An array of user ids (csv is deprecated)
1731    * @param array/string $fields  An array of info field names desired (csv is deprecated)
1732    *
1733    * @return array  An array of user objects
1734    */
1735   public function &users_getStandardInfo($uids, $fields) {
1736     return $this->call_method('facebook.users.getStandardInfo',
1737                               array('uids' => $uids,
1738                                     'fields' => $fields));
1739   }
1740
1741   /**
1742    * Returns the user corresponding to the current session object.
1743    *
1744    * @return integer  User id
1745    */
1746   public function &users_getLoggedInUser() {
1747     return $this->call_method('facebook.users.getLoggedInUser');
1748   }
1749
1750   /**
1751    * Returns 1 if the user has the specified permission, 0 otherwise.
1752    * http://wiki.developers.facebook.com/index.php/Users.hasAppPermission
1753    *
1754    * @return integer  1 or 0
1755    */
1756   public function &users_hasAppPermission($ext_perm, $uid=null) {
1757     return $this->call_method('facebook.users.hasAppPermission',
1758         array('ext_perm' => $ext_perm, 'uid' => $uid));
1759   }
1760
1761   /**
1762    * Returns whether or not the user corresponding to the current
1763    * session object has the give the app basic authorization.
1764    *
1765    * @return boolean  true if the user has authorized the app
1766    */
1767   public function &users_isAppUser($uid=null) {
1768     if ($uid === null && isset($this->is_user)) {
1769       return $this->is_user;
1770     }
1771
1772     return $this->call_method('facebook.users.isAppUser', array('uid' => $uid));
1773   }
1774
1775   /**
1776    * Returns whether or not the user corresponding to the current
1777    * session object is verified by Facebook. See the documentation
1778    * for Users.isVerified for details.
1779    *
1780    * @return boolean  true if the user is verified
1781    */
1782   public function &users_isVerified() {
1783     return $this->call_method('facebook.users.isVerified');
1784   }
1785
1786   /**
1787    * Sets the users' current status message. Message does NOT contain the
1788    * word "is" , so make sure to include a verb.
1789    *
1790    * Example: setStatus("is loving the API!")
1791    * will produce the status "Luke is loving the API!"
1792    *
1793    * @param string $status                text-only message to set
1794    * @param int    $uid                   user to set for (defaults to the
1795    *                                      logged-in user)
1796    * @param bool   $clear                 whether or not to clear the status,
1797    *                                      instead of setting it
1798    * @param bool   $status_includes_verb  if true, the word "is" will *not* be
1799    *                                      prepended to the status message
1800    *
1801    * @return boolean
1802    */
1803   public function &users_setStatus($status,
1804                                    $uid = null,
1805                                    $clear = false,
1806                                    $status_includes_verb = true) {
1807     $args = array(
1808       'status' => $status,
1809       'uid' => $uid,
1810       'clear' => $clear,
1811       'status_includes_verb' => $status_includes_verb,
1812     );
1813     return $this->call_method('facebook.users.setStatus', $args);
1814   }
1815
1816   /**
1817    * Gets the comments for a particular xid. This is essentially a wrapper
1818    * around the comment FQL table.
1819    *
1820    * @param string $xid external id associated with the comments
1821    *
1822    * @return array of comment objects
1823    */
1824   public function &comments_get($xid) {
1825     $args = array('xid' => $xid);
1826     return $this->call_method('facebook.comments.get', $args);
1827   }
1828
1829   /**
1830    * Add a comment to a particular xid on behalf of a user. If called
1831    * without an app_secret (with session secret), this will only work
1832    * for the session user.
1833    *
1834    * @param string $xid   external id associated with the comments
1835    * @param string $text  text of the comment
1836    * @param int    $uid   user adding the comment (def: session user)
1837    * @param string $title optional title for the stream story
1838    * @param string $url   optional url for the stream story
1839    * @param bool   $publish_to_stream publish a feed story about this comment?
1840    *                      a link will be generated to title/url in the story
1841    *
1842    * @return string comment_id associated with the comment
1843    */
1844   public function &comments_add($xid, $text, $uid=0, $title='', $url='',
1845                                 $publish_to_stream=false) {
1846     $args = array(
1847       'xid'               => $xid,
1848       'uid'               => $this->get_uid($uid),
1849       'text'              => $text,
1850       'title'             => $title,
1851       'url'               => $url,
1852       'publish_to_stream' => $publish_to_stream);
1853
1854     return $this->call_method('facebook.comments.add', $args);
1855   }
1856
1857   /**
1858    * Remove a particular comment.
1859    *
1860    * @param string $xid        the external id associated with the comments
1861    * @param string $comment_id id of the comment to remove (returned by
1862    *                           comments.add and comments.get)
1863    *
1864    * @return boolean
1865    */
1866   public function &comments_remove($xid, $comment_id) {
1867     $args = array(
1868       'xid'        => $xid,
1869       'comment_id' => $comment_id);
1870     return $this->call_method('facebook.comments.remove', $args);
1871   }
1872
1873   /**
1874    * Gets the stream on behalf of a user using a set of users. This
1875    * call will return the latest $limit queries between $start_time
1876    * and $end_time.
1877    *
1878    * @param int    $viewer_id  user making the call (def: session)
1879    * @param array  $source_ids users/pages to look at (def: all connections)
1880    * @param int    $start_time start time to look for stories (def: 1 day ago)
1881    * @param int    $end_time   end time to look for stories (def: now)
1882    * @param int    $limit      number of stories to attempt to fetch (def: 30)
1883    * @param string $filter_key key returned by stream.getFilters to fetch
1884    * @param array  $metadata   metadata to include with the return, allows
1885    *                           requested metadata to be returned, such as
1886    *                           profiles, albums, photo_tags
1887    *
1888    * @return array(
1889    *           'posts'      => array of posts,
1890    *           // if requested, the following data may be returned
1891    *           'profiles'   => array of profile metadata of users/pages in posts
1892    *           'albums'     => array of album metadata in posts
1893    *           'photo_tags' => array of photo_tags for photos in posts
1894    *         )
1895    */
1896   public function &stream_get($viewer_id = null,
1897                               $source_ids = null,
1898                               $start_time = 0,
1899                               $end_time = 0,
1900                               $limit = 30,
1901                               $filter_key = '',
1902                               $exportable_only = false,
1903                               $metadata = null,
1904                               $post_ids = null) {
1905     $args = array(
1906       'viewer_id'  => $viewer_id,
1907       'source_ids' => $source_ids,
1908       'start_time' => $start_time,
1909       'end_time'   => $end_time,
1910       'limit'      => $limit,
1911       'filter_key' => $filter_key,
1912       'exportable_only' => $exportable_only,
1913       'metadata' => $metadata,
1914       'post_ids' => $post_ids);
1915     return $this->call_method('facebook.stream.get', $args);
1916   }
1917
1918   /**
1919    * Gets the filters (with relevant filter keys for stream.get) for a
1920    * particular user. These filters are typical things like news feed,
1921    * friend lists, networks. They can be used to filter the stream
1922    * without complex queries to determine which ids belong in which groups.
1923    *
1924    * @param int $uid user to get filters for
1925    *
1926    * @return array of stream filter objects
1927    */
1928   public function &stream_getFilters($uid = null) {
1929     $args = array('uid' => $uid);
1930     return $this->call_method('facebook.stream.getFilters', $args);
1931   }
1932
1933   /**
1934    * Gets the full comments given a post_id from stream.get or the
1935    * stream FQL table. Initially, only a set of preview comments are
1936    * returned because some posts can have many comments.
1937    *
1938    * @param string $post_id id of the post to get comments for
1939    *
1940    * @return array of comment objects
1941    */
1942   public function &stream_getComments($post_id) {
1943     $args = array('post_id' => $post_id);
1944     return $this->call_method('facebook.stream.getComments', $args);
1945   }
1946
1947   /**
1948    * Sets the FBML for the profile of the user attached to this session.
1949    *
1950    * @param   string   $markup           The FBML that describes the profile
1951    *                                     presence of this app for the user
1952    * @param   int      $uid              The user
1953    * @param   string   $profile          Profile FBML
1954    * @param   string   $profile_action   Profile action FBML (deprecated)
1955    * @param   string   $mobile_profile   Mobile profile FBML
1956    * @param   string   $profile_main     Main Tab profile FBML
1957    *
1958    * @return  array  A list of strings describing any compile errors for the
1959    *                 submitted FBML
1960    */
1961   public function profile_setFBML($markup,
1962                            $uid=null,
1963                            $profile='',
1964                            $profile_action='',
1965                            $mobile_profile='',
1966                            $profile_main='') {
1967     return $this->call_method('facebook.profile.setFBML',
1968         array('markup' => $markup,
1969               'uid' => $uid,
1970               'profile' => $profile,
1971               'profile_action' => $profile_action,
1972               'mobile_profile' => $mobile_profile,
1973               'profile_main' => $profile_main));
1974   }
1975
1976   /**
1977    * Gets the FBML for the profile box that is currently set for a user's
1978    * profile (your application set the FBML previously by calling the
1979    * profile.setFBML method).
1980    *
1981    * @param int $uid   (Optional) User id to lookup; defaults to session.
1982    * @param int $type  (Optional) 1 for original style, 2 for profile_main boxes
1983    *
1984    * @return string  The FBML
1985    */
1986   public function &profile_getFBML($uid=null, $type=null) {
1987     return $this->call_method('facebook.profile.getFBML',
1988         array('uid' => $uid,
1989               'type' => $type));
1990   }
1991
1992   /**
1993    * Returns the specified user's application info section for the calling
1994    * application. These info sections have either been set via a previous
1995    * profile.setInfo call or by the user editing them directly.
1996    *
1997    * @param int $uid  (Optional) User id to lookup; defaults to session.
1998    *
1999    * @return array  Info fields for the current user.  See wiki for structure:
2000    *
2001    *  http://wiki.developers.facebook.com/index.php/Profile.getInfo
2002    *
2003    */
2004   public function &profile_getInfo($uid=null) {
2005     return $this->call_method('facebook.profile.getInfo',
2006         array('uid' => $uid));
2007   }
2008
2009   /**
2010    * Returns the options associated with the specified info field for an
2011    * application info section.
2012    *
2013    * @param string $field  The title of the field
2014    *
2015    * @return array  An array of info options.
2016    */
2017   public function &profile_getInfoOptions($field) {
2018     return $this->call_method('facebook.profile.getInfoOptions',
2019         array('field' => $field));
2020   }
2021
2022   /**
2023    * Configures an application info section that the specified user can install
2024    * on the Info tab of her profile.  For details on the structure of an info
2025    * field, please see:
2026    *
2027    *  http://wiki.developers.facebook.com/index.php/Profile.setInfo
2028    *
2029    * @param string $title       Title / header of the info section
2030    * @param int $type           1 for text-only, 5 for thumbnail views
2031    * @param array $info_fields  An array of info fields. See wiki for details.
2032    * @param int $uid            (Optional)
2033    *
2034    * @return bool  true on success
2035    */
2036   public function &profile_setInfo($title, $type, $info_fields, $uid=null) {
2037     return $this->call_method('facebook.profile.setInfo',
2038         array('uid' => $uid,
2039               'type' => $type,
2040               'title'   => $title,
2041               'info_fields' => json_encode($info_fields)));
2042   }
2043
2044   /**
2045    * Specifies the objects for a field for an application info section. These
2046    * options populate the typeahead for a thumbnail.
2047    *
2048    * @param string $field   The title of the field
2049    * @param array $options  An array of items for a thumbnail, including
2050    *                        'label', 'link', and optionally 'image',
2051    *                        'description' and 'sublabel'
2052    *
2053    * @return bool  true on success
2054    */
2055   public function profile_setInfoOptions($field, $options) {
2056     return $this->call_method('facebook.profile.setInfoOptions',
2057         array('field'   => $field,
2058               'options' => json_encode($options)));
2059   }
2060
2061   /////////////////////////////////////////////////////////////////////////////
2062   // Data Store API
2063
2064   /**
2065    * Set a user preference.
2066    *
2067    * @param  pref_id    preference identifier (0-200)
2068    * @param  value      preferece's value
2069    * @param  uid        the user id (defaults to current session user)
2070    * @error
2071    *    API_EC_DATA_DATABASE_ERROR
2072    *    API_EC_PARAM
2073    *    API_EC_DATA_QUOTA_EXCEEDED
2074    *    API_EC_DATA_UNKNOWN_ERROR
2075    *    API_EC_PERMISSION_OTHER_USER
2076    */
2077   public function &data_setUserPreference($pref_id, $value, $uid = null) {
2078     return $this->call_method('facebook.data.setUserPreference',
2079        array('pref_id' => $pref_id,
2080              'value' => $value,
2081              'uid' => $this->get_uid($uid)));
2082   }
2083
2084   /**
2085    * Set a user's all preferences for this application.
2086    *
2087    * @param  values     preferece values in an associative arrays
2088    * @param  replace    whether to replace all existing preferences or
2089    *                    merge into them.
2090    * @param  uid        the user id (defaults to current session user)
2091    * @error
2092    *    API_EC_DATA_DATABASE_ERROR
2093    *    API_EC_PARAM
2094    *    API_EC_DATA_QUOTA_EXCEEDED
2095    *    API_EC_DATA_UNKNOWN_ERROR
2096    *    API_EC_PERMISSION_OTHER_USER
2097    */
2098   public function &data_setUserPreferences($values,
2099                                            $replace = false,
2100                                            $uid = null) {
2101     return $this->call_method('facebook.data.setUserPreferences',
2102        array('values' => json_encode($values),
2103              'replace' => $replace,
2104              'uid' => $this->get_uid($uid)));
2105   }
2106
2107   /**
2108    * Get a user preference.
2109    *
2110    * @param  pref_id    preference identifier (0-200)
2111    * @param  uid        the user id (defaults to current session user)
2112    * @return            preference's value
2113    * @error
2114    *    API_EC_DATA_DATABASE_ERROR
2115    *    API_EC_PARAM
2116    *    API_EC_DATA_QUOTA_EXCEEDED
2117    *    API_EC_DATA_UNKNOWN_ERROR
2118    *    API_EC_PERMISSION_OTHER_USER
2119    */
2120   public function &data_getUserPreference($pref_id, $uid = null) {
2121     return $this->call_method('facebook.data.getUserPreference',
2122        array('pref_id' => $pref_id,
2123              'uid' => $this->get_uid($uid)));
2124   }
2125
2126   /**
2127    * Get a user preference.
2128    *
2129    * @param  uid        the user id (defaults to current session user)
2130    * @return            preference values
2131    * @error
2132    *    API_EC_DATA_DATABASE_ERROR
2133    *    API_EC_DATA_QUOTA_EXCEEDED
2134    *    API_EC_DATA_UNKNOWN_ERROR
2135    *    API_EC_PERMISSION_OTHER_USER
2136    */
2137   public function &data_getUserPreferences($uid = null) {
2138     return $this->call_method('facebook.data.getUserPreferences',
2139        array('uid' => $this->get_uid($uid)));
2140   }
2141
2142   /**
2143    * Create a new object type.
2144    *
2145    * @param  name       object type's name
2146    * @error
2147    *    API_EC_DATA_DATABASE_ERROR
2148    *    API_EC_DATA_OBJECT_ALREADY_EXISTS
2149    *    API_EC_PARAM
2150    *    API_EC_PERMISSION
2151    *    API_EC_DATA_INVALID_OPERATION
2152    *    API_EC_DATA_QUOTA_EXCEEDED
2153    *    API_EC_DATA_UNKNOWN_ERROR
2154    */
2155   public function &data_createObjectType($name) {
2156     return $this->call_method('facebook.data.createObjectType',
2157        array('name' => $name));
2158   }
2159
2160   /**
2161    * Delete an object type.
2162    *
2163    * @param  obj_type       object type's name
2164    * @error
2165    *    API_EC_DATA_DATABASE_ERROR
2166    *    API_EC_DATA_OBJECT_NOT_FOUND
2167    *    API_EC_PARAM
2168    *    API_EC_PERMISSION
2169    *    API_EC_DATA_INVALID_OPERATION
2170    *    API_EC_DATA_QUOTA_EXCEEDED
2171    *    API_EC_DATA_UNKNOWN_ERROR
2172    */
2173   public function &data_dropObjectType($obj_type) {
2174     return $this->call_method('facebook.data.dropObjectType',
2175        array('obj_type' => $obj_type));
2176   }
2177
2178   /**
2179    * Rename an object type.
2180    *
2181    * @param  obj_type       object type's name
2182    * @param  new_name       new object type's name
2183    * @error
2184    *    API_EC_DATA_DATABASE_ERROR
2185    *    API_EC_DATA_OBJECT_NOT_FOUND
2186    *    API_EC_DATA_OBJECT_ALREADY_EXISTS
2187    *    API_EC_PARAM
2188    *    API_EC_PERMISSION
2189    *    API_EC_DATA_INVALID_OPERATION
2190    *    API_EC_DATA_QUOTA_EXCEEDED
2191    *    API_EC_DATA_UNKNOWN_ERROR
2192    */
2193   public function &data_renameObjectType($obj_type, $new_name) {
2194     return $this->call_method('facebook.data.renameObjectType',
2195        array('obj_type' => $obj_type,
2196              'new_name' => $new_name));
2197   }
2198
2199   /**
2200    * Add a new property to an object type.
2201    *
2202    * @param  obj_type       object type's name
2203    * @param  prop_name      name of the property to add
2204    * @param  prop_type      1: integer; 2: string; 3: text blob
2205    * @error
2206    *    API_EC_DATA_DATABASE_ERROR
2207    *    API_EC_DATA_OBJECT_ALREADY_EXISTS
2208    *    API_EC_PARAM
2209    *    API_EC_PERMISSION
2210    *    API_EC_DATA_INVALID_OPERATION
2211    *    API_EC_DATA_QUOTA_EXCEEDED
2212    *    API_EC_DATA_UNKNOWN_ERROR
2213    */
2214   public function &data_defineObjectProperty($obj_type,
2215                                              $prop_name,
2216                                              $prop_type) {
2217     return $this->call_method('facebook.data.defineObjectProperty',
2218        array('obj_type' => $obj_type,
2219              'prop_name' => $prop_name,
2220              'prop_type' => $prop_type));
2221   }
2222
2223   /**
2224    * Remove a previously defined property from an object type.
2225    *
2226    * @param  obj_type      object type's name
2227    * @param  prop_name     name of the property to remove
2228    * @error
2229    *    API_EC_DATA_DATABASE_ERROR
2230    *    API_EC_DATA_OBJECT_NOT_FOUND
2231    *    API_EC_PARAM
2232    *    API_EC_PERMISSION
2233    *    API_EC_DATA_INVALID_OPERATION
2234    *    API_EC_DATA_QUOTA_EXCEEDED
2235    *    API_EC_DATA_UNKNOWN_ERROR
2236    */
2237   public function &data_undefineObjectProperty($obj_type, $prop_name) {
2238     return $this->call_method('facebook.data.undefineObjectProperty',
2239        array('obj_type' => $obj_type,
2240              'prop_name' => $prop_name));
2241   }
2242
2243   /**
2244    * Rename a previously defined property of an object type.
2245    *
2246    * @param  obj_type      object type's name
2247    * @param  prop_name     name of the property to rename
2248    * @param  new_name      new name to use
2249    * @error
2250    *    API_EC_DATA_DATABASE_ERROR
2251    *    API_EC_DATA_OBJECT_NOT_FOUND
2252    *    API_EC_DATA_OBJECT_ALREADY_EXISTS
2253    *    API_EC_PARAM
2254    *    API_EC_PERMISSION
2255    *    API_EC_DATA_INVALID_OPERATION
2256    *    API_EC_DATA_QUOTA_EXCEEDED
2257    *    API_EC_DATA_UNKNOWN_ERROR
2258    */
2259   public function &data_renameObjectProperty($obj_type, $prop_name,
2260                                             $new_name) {
2261     return $this->call_method('facebook.data.renameObjectProperty',
2262        array('obj_type' => $obj_type,
2263              'prop_name' => $prop_name,
2264              'new_name' => $new_name));
2265   }
2266
2267   /**
2268    * Retrieve a list of all object types that have defined for the application.
2269    *
2270    * @return               a list of object type names
2271    * @error
2272    *    API_EC_DATA_DATABASE_ERROR
2273    *    API_EC_PERMISSION
2274    *    API_EC_DATA_QUOTA_EXCEEDED
2275    *    API_EC_DATA_UNKNOWN_ERROR
2276    */
2277   public function &data_getObjectTypes() {
2278     return $this->call_method('facebook.data.getObjectTypes');
2279   }
2280
2281   /**
2282    * Get definitions of all properties of an object type.
2283    *
2284    * @param obj_type       object type's name
2285    * @return               pairs of property name and property types
2286    * @error
2287    *    API_EC_DATA_DATABASE_ERROR
2288    *    API_EC_PARAM
2289    *    API_EC_PERMISSION
2290    *    API_EC_DATA_OBJECT_NOT_FOUND
2291    *    API_EC_DATA_QUOTA_EXCEEDED
2292    *    API_EC_DATA_UNKNOWN_ERROR
2293    */
2294   public function &data_getObjectType($obj_type) {
2295     return $this->call_method('facebook.data.getObjectType',
2296        array('obj_type' => $obj_type));
2297   }
2298
2299   /**
2300    * Create a new object.
2301    *
2302    * @param  obj_type      object type's name
2303    * @param  properties    (optional) properties to set initially
2304    * @return               newly created object's id
2305    * @error
2306    *    API_EC_DATA_DATABASE_ERROR
2307    *    API_EC_PARAM
2308    *    API_EC_PERMISSION
2309    *    API_EC_DATA_INVALID_OPERATION
2310    *    API_EC_DATA_QUOTA_EXCEEDED
2311    *    API_EC_DATA_UNKNOWN_ERROR
2312    */
2313   public function &data_createObject($obj_type, $properties = null) {
2314     return $this->call_method('facebook.data.createObject',
2315        array('obj_type' => $obj_type,
2316              'properties' => json_encode($properties)));
2317   }
2318
2319   /**
2320    * Update an existing object.
2321    *
2322    * @param  obj_id        object's id
2323    * @param  properties    new properties
2324    * @param  replace       true for replacing existing properties;
2325    *                       false for merging
2326    * @error
2327    *    API_EC_DATA_DATABASE_ERROR
2328    *    API_EC_DATA_OBJECT_NOT_FOUND
2329    *    API_EC_PARAM
2330    *    API_EC_PERMISSION
2331    *    API_EC_DATA_INVALID_OPERATION
2332    *    API_EC_DATA_QUOTA_EXCEEDED
2333    *    API_EC_DATA_UNKNOWN_ERROR
2334    */
2335   public function &data_updateObject($obj_id, $properties, $replace = false) {
2336     return $this->call_method('facebook.data.updateObject',
2337        array('obj_id' => $obj_id,
2338              'properties' => json_encode($properties),
2339              'replace' => $replace));
2340   }
2341
2342   /**
2343    * Delete an existing object.
2344    *
2345    * @param  obj_id        object's id
2346    * @error
2347    *    API_EC_DATA_DATABASE_ERROR
2348    *    API_EC_DATA_OBJECT_NOT_FOUND
2349    *    API_EC_PARAM
2350    *    API_EC_PERMISSION
2351    *    API_EC_DATA_INVALID_OPERATION
2352    *    API_EC_DATA_QUOTA_EXCEEDED
2353    *    API_EC_DATA_UNKNOWN_ERROR
2354    */
2355   public function &data_deleteObject($obj_id) {
2356     return $this->call_method('facebook.data.deleteObject',
2357        array('obj_id' => $obj_id));
2358   }
2359
2360   /**
2361    * Delete a list of objects.
2362    *
2363    * @param  obj_ids       objects to delete
2364    * @error
2365    *    API_EC_DATA_DATABASE_ERROR
2366    *    API_EC_PARAM
2367    *    API_EC_PERMISSION
2368    *    API_EC_DATA_INVALID_OPERATION
2369    *    API_EC_DATA_QUOTA_EXCEEDED
2370    *    API_EC_DATA_UNKNOWN_ERROR
2371    */
2372   public function &data_deleteObjects($obj_ids) {
2373     return $this->call_method('facebook.data.deleteObjects',
2374        array('obj_ids' => json_encode($obj_ids)));
2375   }
2376
2377   /**
2378    * Get a single property value of an object.
2379    *
2380    * @param  obj_id        object's id
2381    * @param  prop_name     individual property's name
2382    * @return               individual property's value
2383    * @error
2384    *    API_EC_DATA_DATABASE_ERROR
2385    *    API_EC_DATA_OBJECT_NOT_FOUND
2386    *    API_EC_PARAM
2387    *    API_EC_PERMISSION
2388    *    API_EC_DATA_INVALID_OPERATION
2389    *    API_EC_DATA_QUOTA_EXCEEDED
2390    *    API_EC_DATA_UNKNOWN_ERROR
2391    */
2392   public function &data_getObjectProperty($obj_id, $prop_name) {
2393     return $this->call_method('facebook.data.getObjectProperty',
2394        array('obj_id' => $obj_id,
2395              'prop_name' => $prop_name));
2396   }
2397
2398   /**
2399    * Get properties of an object.
2400    *
2401    * @param  obj_id      object's id
2402    * @param  prop_names  (optional) properties to return; null for all.
2403    * @return             specified properties of an object
2404    * @error
2405    *    API_EC_DATA_DATABASE_ERROR
2406    *    API_EC_DATA_OBJECT_NOT_FOUND
2407    *    API_EC_PARAM
2408    *    API_EC_PERMISSION
2409    *    API_EC_DATA_INVALID_OPERATION
2410    *    API_EC_DATA_QUOTA_EXCEEDED
2411    *    API_EC_DATA_UNKNOWN_ERROR
2412    */
2413   public function &data_getObject($obj_id, $prop_names = null) {
2414     return $this->call_method('facebook.data.getObject',
2415        array('obj_id' => $obj_id,
2416              'prop_names' => json_encode($prop_names)));
2417   }
2418
2419   /**
2420    * Get properties of a list of objects.
2421    *
2422    * @param  obj_ids     object ids
2423    * @param  prop_names  (optional) properties to return; null for all.
2424    * @return             specified properties of an object
2425    * @error
2426    *    API_EC_DATA_DATABASE_ERROR
2427    *    API_EC_DATA_OBJECT_NOT_FOUND
2428    *    API_EC_PARAM
2429    *    API_EC_PERMISSION
2430    *    API_EC_DATA_INVALID_OPERATION
2431    *    API_EC_DATA_QUOTA_EXCEEDED
2432    *    API_EC_DATA_UNKNOWN_ERROR
2433    */
2434   public function &data_getObjects($obj_ids, $prop_names = null) {
2435     return $this->call_method('facebook.data.getObjects',
2436        array('obj_ids' => json_encode($obj_ids),
2437              'prop_names' => json_encode($prop_names)));
2438   }
2439
2440   /**
2441    * Set a single property value of an object.
2442    *
2443    * @param  obj_id        object's id
2444    * @param  prop_name     individual property's name
2445    * @param  prop_value    new value to set
2446    * @error
2447    *    API_EC_DATA_DATABASE_ERROR
2448    *    API_EC_DATA_OBJECT_NOT_FOUND
2449    *    API_EC_PARAM
2450    *    API_EC_PERMISSION
2451    *    API_EC_DATA_INVALID_OPERATION
2452    *    API_EC_DATA_QUOTA_EXCEEDED
2453    *    API_EC_DATA_UNKNOWN_ERROR
2454    */
2455   public function &data_setObjectProperty($obj_id, $prop_name,
2456                                          $prop_value) {
2457     return $this->call_method('facebook.data.setObjectProperty',
2458        array('obj_id' => $obj_id,
2459              'prop_name' => $prop_name,
2460              'prop_value' => $prop_value));
2461   }
2462
2463   /**
2464    * Read hash value by key.
2465    *
2466    * @param  obj_type      object type's name
2467    * @param  key           hash key
2468    * @param  prop_name     (optional) individual property's name
2469    * @return               hash value
2470    * @error
2471    *    API_EC_DATA_DATABASE_ERROR
2472    *    API_EC_PARAM
2473    *    API_EC_PERMISSION
2474    *    API_EC_DATA_INVALID_OPERATION
2475    *    API_EC_DATA_QUOTA_EXCEEDED
2476    *    API_EC_DATA_UNKNOWN_ERROR
2477    */
2478   public function &data_getHashValue($obj_type, $key, $prop_name = null) {
2479     return $this->call_method('facebook.data.getHashValue',
2480        array('obj_type' => $obj_type,
2481              'key' => $key,
2482              'prop_name' => $prop_name));
2483   }
2484
2485   /**
2486    * Write hash value by key.
2487    *
2488    * @param  obj_type      object type's name
2489    * @param  key           hash key
2490    * @param  value         hash value
2491    * @param  prop_name     (optional) individual property's name
2492    * @error
2493    *    API_EC_DATA_DATABASE_ERROR
2494    *    API_EC_PARAM
2495    *    API_EC_PERMISSION
2496    *    API_EC_DATA_INVALID_OPERATION
2497    *    API_EC_DATA_QUOTA_EXCEEDED
2498    *    API_EC_DATA_UNKNOWN_ERROR
2499    */
2500   public function &data_setHashValue($obj_type,
2501                                      $key,
2502                                      $value,
2503                                      $prop_name = null) {
2504     return $this->call_method('facebook.data.setHashValue',
2505        array('obj_type' => $obj_type,
2506              'key' => $key,
2507              'value' => $value,
2508              'prop_name' => $prop_name));
2509   }
2510
2511   /**
2512    * Increase a hash value by specified increment atomically.
2513    *
2514    * @param  obj_type      object type's name
2515    * @param  key           hash key
2516    * @param  prop_name     individual property's name
2517    * @param  increment     (optional) default is 1
2518    * @return               incremented hash value
2519    * @error
2520    *    API_EC_DATA_DATABASE_ERROR
2521    *    API_EC_PARAM
2522    *    API_EC_PERMISSION
2523    *    API_EC_DATA_INVALID_OPERATION
2524    *    API_EC_DATA_QUOTA_EXCEEDED
2525    *    API_EC_DATA_UNKNOWN_ERROR
2526    */
2527   public function &data_incHashValue($obj_type,
2528                                      $key,
2529                                      $prop_name,
2530                                      $increment = 1) {
2531     return $this->call_method('facebook.data.incHashValue',
2532        array('obj_type' => $obj_type,
2533              'key' => $key,
2534              'prop_name' => $prop_name,
2535              'increment' => $increment));
2536   }
2537
2538   /**
2539    * Remove a hash key and its values.
2540    *
2541    * @param  obj_type    object type's name
2542    * @param  key         hash key
2543    * @error
2544    *    API_EC_DATA_DATABASE_ERROR
2545    *    API_EC_PARAM
2546    *    API_EC_PERMISSION
2547    *    API_EC_DATA_INVALID_OPERATION
2548    *    API_EC_DATA_QUOTA_EXCEEDED
2549    *    API_EC_DATA_UNKNOWN_ERROR
2550    */
2551   public function &data_removeHashKey($obj_type, $key) {
2552     return $this->call_method('facebook.data.removeHashKey',
2553        array('obj_type' => $obj_type,
2554              'key' => $key));
2555   }
2556
2557   /**
2558    * Remove hash keys and their values.
2559    *
2560    * @param  obj_type    object type's name
2561    * @param  keys        hash keys
2562    * @error
2563    *    API_EC_DATA_DATABASE_ERROR
2564    *    API_EC_PARAM
2565    *    API_EC_PERMISSION
2566    *    API_EC_DATA_INVALID_OPERATION
2567    *    API_EC_DATA_QUOTA_EXCEEDED
2568    *    API_EC_DATA_UNKNOWN_ERROR
2569    */
2570   public function &data_removeHashKeys($obj_type, $keys) {
2571     return $this->call_method('facebook.data.removeHashKeys',
2572        array('obj_type' => $obj_type,
2573              'keys' => json_encode($keys)));
2574   }
2575
2576   /**
2577    * Define an object association.
2578    *
2579    * @param  name        name of this association
2580    * @param  assoc_type  1: one-way 2: two-way symmetric 3: two-way asymmetric
2581    * @param  assoc_info1 needed info about first object type
2582    * @param  assoc_info2 needed info about second object type
2583    * @param  inverse     (optional) name of reverse association
2584    * @error
2585    *    API_EC_DATA_DATABASE_ERROR
2586    *    API_EC_DATA_OBJECT_ALREADY_EXISTS
2587    *    API_EC_PARAM
2588    *    API_EC_PERMISSION
2589    *    API_EC_DATA_INVALID_OPERATION
2590    *    API_EC_DATA_QUOTA_EXCEEDED
2591    *    API_EC_DATA_UNKNOWN_ERROR
2592    */
2593   public function &data_defineAssociation($name, $assoc_type, $assoc_info1,
2594                                          $assoc_info2, $inverse = null) {
2595     return $this->call_method('facebook.data.defineAssociation',
2596        array('name' => $name,
2597              'assoc_type' => $assoc_type,
2598              'assoc_info1' => json_encode($assoc_info1),
2599              'assoc_info2' => json_encode($assoc_info2),
2600              'inverse' => $inverse));
2601   }
2602
2603   /**
2604    * Undefine an object association.
2605    *
2606    * @param  name        name of this association
2607    * @error
2608    *    API_EC_DATA_DATABASE_ERROR
2609    *    API_EC_DATA_OBJECT_NOT_FOUND
2610    *    API_EC_PARAM
2611    *    API_EC_PERMISSION
2612    *    API_EC_DATA_INVALID_OPERATION
2613    *    API_EC_DATA_QUOTA_EXCEEDED
2614    *    API_EC_DATA_UNKNOWN_ERROR
2615    */
2616   public function &data_undefineAssociation($name) {
2617     return $this->call_method('facebook.data.undefineAssociation',
2618        array('name' => $name));
2619   }
2620
2621   /**
2622    * Rename an object association or aliases.
2623    *
2624    * @param  name        name of this association
2625    * @param  new_name    (optional) new name of this association
2626    * @param  new_alias1  (optional) new alias for object type 1
2627    * @param  new_alias2  (optional) new alias for object type 2
2628    * @error
2629    *    API_EC_DATA_DATABASE_ERROR
2630    *    API_EC_DATA_OBJECT_ALREADY_EXISTS
2631    *    API_EC_DATA_OBJECT_NOT_FOUND
2632    *    API_EC_PARAM
2633    *    API_EC_PERMISSION
2634    *    API_EC_DATA_INVALID_OPERATION
2635    *    API_EC_DATA_QUOTA_EXCEEDED
2636    *    API_EC_DATA_UNKNOWN_ERROR
2637    */
2638   public function &data_renameAssociation($name, $new_name, $new_alias1 = null,
2639                                          $new_alias2 = null) {
2640     return $this->call_method('facebook.data.renameAssociation',
2641        array('name' => $name,
2642              'new_name' => $new_name,
2643              'new_alias1' => $new_alias1,
2644              'new_alias2' => $new_alias2));
2645   }
2646
2647   /**
2648    * Get definition of an object association.
2649    *
2650    * @param  name        name of this association
2651    * @return             specified association
2652    * @error
2653    *    API_EC_DATA_DATABASE_ERROR
2654    *    API_EC_DATA_OBJECT_NOT_FOUND
2655    *    API_EC_PARAM
2656    *    API_EC_PERMISSION
2657    *    API_EC_DATA_QUOTA_EXCEEDED
2658    *    API_EC_DATA_UNKNOWN_ERROR
2659    */
2660   public function &data_getAssociationDefinition($name) {
2661     return $this->call_method('facebook.data.getAssociationDefinition',
2662        array('name' => $name));
2663   }
2664
2665   /**
2666    * Get definition of all associations.
2667    *
2668    * @return             all defined associations
2669    * @error
2670    *    API_EC_DATA_DATABASE_ERROR
2671    *    API_EC_PERMISSION
2672    *    API_EC_DATA_QUOTA_EXCEEDED
2673    *    API_EC_DATA_UNKNOWN_ERROR
2674    */
2675   public function &data_getAssociationDefinitions() {
2676     return $this->call_method('facebook.data.getAssociationDefinitions',
2677        array());
2678   }
2679
2680   /**
2681    * Create or modify an association between two objects.
2682    *
2683    * @param  name        name of association
2684    * @param  obj_id1     id of first object
2685    * @param  obj_id2     id of second object
2686    * @param  data        (optional) extra string data to store
2687    * @param  assoc_time  (optional) extra time data; default to creation time
2688    * @error
2689    *    API_EC_DATA_DATABASE_ERROR
2690    *    API_EC_PARAM
2691    *    API_EC_PERMISSION
2692    *    API_EC_DATA_INVALID_OPERATION
2693    *    API_EC_DATA_QUOTA_EXCEEDED
2694    *    API_EC_DATA_UNKNOWN_ERROR
2695    */
2696   public function &data_setAssociation($name, $obj_id1, $obj_id2, $data = null,
2697                                       $assoc_time = null) {
2698     return $this->call_method('facebook.data.setAssociation',
2699        array('name' => $name,
2700              'obj_id1' => $obj_id1,
2701              'obj_id2' => $obj_id2,
2702              'data' => $data,
2703              'assoc_time' => $assoc_time));
2704   }
2705
2706   /**
2707    * Create or modify associations between objects.
2708    *
2709    * @param  assocs      associations to set
2710    * @param  name        (optional) name of association
2711    * @error
2712    *    API_EC_DATA_DATABASE_ERROR
2713    *    API_EC_PARAM
2714    *    API_EC_PERMISSION
2715    *    API_EC_DATA_INVALID_OPERATION
2716    *    API_EC_DATA_QUOTA_EXCEEDED
2717    *    API_EC_DATA_UNKNOWN_ERROR
2718    */
2719   public function &data_setAssociations($assocs, $name = null) {
2720     return $this->call_method('facebook.data.setAssociations',
2721        array('assocs' => json_encode($assocs),
2722              'name' => $name));
2723   }
2724
2725   /**
2726    * Remove an association between two objects.
2727    *
2728    * @param  name        name of association
2729    * @param  obj_id1     id of first object
2730    * @param  obj_id2     id of second object
2731    * @error
2732    *    API_EC_DATA_DATABASE_ERROR
2733    *    API_EC_DATA_OBJECT_NOT_FOUND
2734    *    API_EC_PARAM
2735    *    API_EC_PERMISSION
2736    *    API_EC_DATA_QUOTA_EXCEEDED
2737    *    API_EC_DATA_UNKNOWN_ERROR
2738    */
2739   public function &data_removeAssociation($name, $obj_id1, $obj_id2) {
2740     return $this->call_method('facebook.data.removeAssociation',
2741        array('name' => $name,
2742              'obj_id1' => $obj_id1,
2743              'obj_id2' => $obj_id2));
2744   }
2745
2746   /**
2747    * Remove associations between objects by specifying pairs of object ids.
2748    *
2749    * @param  assocs      associations to remove
2750    * @param  name        (optional) name of association
2751    * @error
2752    *    API_EC_DATA_DATABASE_ERROR
2753    *    API_EC_DATA_OBJECT_NOT_FOUND
2754    *    API_EC_PARAM
2755    *    API_EC_PERMISSION
2756    *    API_EC_DATA_QUOTA_EXCEEDED
2757    *    API_EC_DATA_UNKNOWN_ERROR
2758    */
2759   public function &data_removeAssociations($assocs, $name = null) {
2760     return $this->call_method('facebook.data.removeAssociations',
2761        array('assocs' => json_encode($assocs),
2762              'name' => $name));
2763   }
2764
2765   /**
2766    * Remove associations between objects by specifying one object id.
2767    *
2768    * @param  name        name of association
2769    * @param  obj_id      who's association to remove
2770    * @error
2771    *    API_EC_DATA_DATABASE_ERROR
2772    *    API_EC_DATA_OBJECT_NOT_FOUND
2773    *    API_EC_PARAM
2774    *    API_EC_PERMISSION
2775    *    API_EC_DATA_INVALID_OPERATION
2776    *    API_EC_DATA_QUOTA_EXCEEDED
2777    *    API_EC_DATA_UNKNOWN_ERROR
2778    */
2779   public function &data_removeAssociatedObjects($name, $obj_id) {
2780     return $this->call_method('facebook.data.removeAssociatedObjects',
2781        array('name' => $name,
2782              'obj_id' => $obj_id));
2783   }
2784
2785   /**
2786    * Retrieve a list of associated objects.
2787    *
2788    * @param  name        name of association
2789    * @param  obj_id      who's association to retrieve
2790    * @param  no_data     only return object ids
2791    * @return             associated objects
2792    * @error
2793    *    API_EC_DATA_DATABASE_ERROR
2794    *    API_EC_DATA_OBJECT_NOT_FOUND
2795    *    API_EC_PARAM
2796    *    API_EC_PERMISSION
2797    *    API_EC_DATA_INVALID_OPERATION
2798    *    API_EC_DATA_QUOTA_EXCEEDED
2799    *    API_EC_DATA_UNKNOWN_ERROR
2800    */
2801   public function &data_getAssociatedObjects($name, $obj_id, $no_data = true) {
2802     return $this->call_method('facebook.data.getAssociatedObjects',
2803        array('name' => $name,
2804              'obj_id' => $obj_id,
2805              'no_data' => $no_data));
2806   }
2807
2808   /**
2809    * Count associated objects.
2810    *
2811    * @param  name        name of association
2812    * @param  obj_id      who's association to retrieve
2813    * @return             associated object's count
2814    * @error
2815    *    API_EC_DATA_DATABASE_ERROR
2816    *    API_EC_DATA_OBJECT_NOT_FOUND
2817    *    API_EC_PARAM
2818    *    API_EC_PERMISSION
2819    *    API_EC_DATA_INVALID_OPERATION
2820    *    API_EC_DATA_QUOTA_EXCEEDED
2821    *    API_EC_DATA_UNKNOWN_ERROR
2822    */
2823   public function &data_getAssociatedObjectCount($name, $obj_id) {
2824     return $this->call_method('facebook.data.getAssociatedObjectCount',
2825        array('name' => $name,
2826              'obj_id' => $obj_id));
2827   }
2828
2829   /**
2830    * Get a list of associated object counts.
2831    *
2832    * @param  name        name of association
2833    * @param  obj_ids     whose association to retrieve
2834    * @return             associated object counts
2835    * @error
2836    *    API_EC_DATA_DATABASE_ERROR
2837    *    API_EC_DATA_OBJECT_NOT_FOUND
2838    *    API_EC_PARAM
2839    *    API_EC_PERMISSION
2840    *    API_EC_DATA_INVALID_OPERATION
2841    *    API_EC_DATA_QUOTA_EXCEEDED
2842    *    API_EC_DATA_UNKNOWN_ERROR
2843    */
2844   public function &data_getAssociatedObjectCounts($name, $obj_ids) {
2845     return $this->call_method('facebook.data.getAssociatedObjectCounts',
2846        array('name' => $name,
2847              'obj_ids' => json_encode($obj_ids)));
2848   }
2849
2850   /**
2851    * Find all associations between two objects.
2852    *
2853    * @param  obj_id1     id of first object
2854    * @param  obj_id2     id of second object
2855    * @param  no_data     only return association names without data
2856    * @return             all associations between objects
2857    * @error
2858    *    API_EC_DATA_DATABASE_ERROR
2859    *    API_EC_PARAM
2860    *    API_EC_PERMISSION
2861    *    API_EC_DATA_QUOTA_EXCEEDED
2862    *    API_EC_DATA_UNKNOWN_ERROR
2863    */
2864   public function &data_getAssociations($obj_id1, $obj_id2, $no_data = true) {
2865     return $this->call_method('facebook.data.getAssociations',
2866        array('obj_id1' => $obj_id1,
2867              'obj_id2' => $obj_id2,
2868              'no_data' => $no_data));
2869   }
2870
2871   /**
2872    * Get the properties that you have set for an app.
2873    *
2874    * @param properties  List of properties names to fetch
2875    *
2876    * @return array  A map from property name to value
2877    */
2878   public function admin_getAppProperties($properties) {
2879     return json_decode(
2880         $this->call_method('facebook.admin.getAppProperties',
2881             array('properties' => json_encode($properties))), true);
2882   }
2883
2884   /**
2885    * Set properties for an app.
2886    *
2887    * @param properties  A map from property names to values
2888    *
2889    * @return bool  true on success
2890    */
2891   public function admin_setAppProperties($properties) {
2892     return $this->call_method('facebook.admin.setAppProperties',
2893        array('properties' => json_encode($properties)));
2894   }
2895
2896   /**
2897    * Sets href and text for a Live Stream Box xid's via link
2898    *
2899    * @param  string  $xid       xid of the Live Stream
2900    * @param  string  $via_href  Href for the via link
2901    * @param  string  $via_text  Text for the via link
2902    *
2903    * @return boolWhether the set was successful
2904    */
2905   public function admin_setLiveStreamViaLink($xid, $via_href, $via_text) {
2906     return $this->call_method('facebook.admin.setLiveStreamViaLink',
2907                               array('xid'      => $xid,
2908                                     'via_href' => $via_href,
2909                                     'via_text' => $via_text));
2910   }
2911
2912   /**
2913    * Gets href and text for a Live Stream Box xid's via link
2914    *
2915    * @param  string  $xid  xid of the Live Stream
2916    *
2917    * @return Array  Associative array with keys 'via_href' and 'via_text'
2918    *                False if there was an error.
2919    */
2920   public function admin_getLiveStreamViaLink($xid) {
2921     return $this->call_method('facebook.admin.getLiveStreamViaLink',
2922                               array('xid' => $xid));
2923   }
2924
2925   /**
2926    * Returns the allocation limit value for a specified integration point name
2927    * Integration point names are defined in lib/api/karma/constants.php in the
2928    * limit_map.
2929    *
2930    * @param string $integration_point_name  Name of an integration point
2931    *                                        (see developer wiki for list).
2932    * @param int    $uid                     Specific user to check the limit.
2933    *
2934    * @return int  Integration point allocation value
2935    */
2936   public function &admin_getAllocation($integration_point_name, $uid=null) {
2937     return $this->call_method('facebook.admin.getAllocation',
2938         array('integration_point_name' => $integration_point_name,
2939               'uid' => $uid));
2940   }
2941
2942   /**
2943    * Returns values for the specified metrics for the current application, in
2944    * the given time range.  The metrics are collected for fixed-length periods,
2945    * and the times represent midnight at the end of each period.
2946    *
2947    * @param start_time  unix time for the start of the range
2948    * @param end_time    unix time for the end of the range
2949    * @param period      number of seconds in the desired period
2950    * @param metrics     list of metrics to look up
2951    *
2952    * @return array  A map of the names and values for those metrics
2953    */
2954   public function &admin_getMetrics($start_time, $end_time, $period, $metrics) {
2955     return $this->call_method('admin.getMetrics',
2956         array('start_time' => $start_time,
2957               'end_time' => $end_time,
2958               'period' => $period,
2959               'metrics' => json_encode($metrics)));
2960   }
2961
2962   /**
2963    * Sets application restriction info.
2964    *
2965    * Applications can restrict themselves to only a limited user demographic
2966    * based on users' age and/or location or based on static predefined types
2967    * specified by facebook for specifying diff age restriction for diff
2968    * locations.
2969    *
2970    * @param array $restriction_info  The age restriction settings to set.
2971    *
2972    * @return bool  true on success
2973    */
2974   public function admin_setRestrictionInfo($restriction_info = null) {
2975     $restriction_str = null;
2976     if (!empty($restriction_info)) {
2977       $restriction_str = json_encode($restriction_info);
2978     }
2979     return $this->call_method('admin.setRestrictionInfo',
2980         array('restriction_str' => $restriction_str));
2981   }
2982
2983   /**
2984    * Gets application restriction info.
2985    *
2986    * Applications can restrict themselves to only a limited user demographic
2987    * based on users' age and/or location or based on static predefined types
2988    * specified by facebook for specifying diff age restriction for diff
2989    * locations.
2990    *
2991    * @return array  The age restriction settings for this application.
2992    */
2993   public function admin_getRestrictionInfo() {
2994     return json_decode(
2995         $this->call_method('admin.getRestrictionInfo'),
2996         true);
2997   }
2998
2999
3000   /**
3001    * Bans a list of users from the app. Banned users can't
3002    * access the app's canvas page and forums.
3003    *
3004    * @param array $uids an array of user ids
3005    * @return bool true on success
3006    */
3007   public function admin_banUsers($uids) {
3008     return $this->call_method(
3009       'admin.banUsers', array('uids' => json_encode($uids)));
3010   }
3011
3012   /**
3013    * Unban users that have been previously banned with
3014    * admin_banUsers().
3015    *
3016    * @param array $uids an array of user ids
3017    * @return bool true on success
3018    */
3019   public function admin_unbanUsers($uids) {
3020     return $this->call_method(
3021       'admin.unbanUsers', array('uids' => json_encode($uids)));
3022   }
3023
3024   /**
3025    * Gets the list of users that have been banned from the application.
3026    * $uids is an optional parameter that filters the result with the list
3027    * of provided user ids. If $uids is provided,
3028    * only banned user ids that are contained in $uids are returned.
3029    *
3030    * @param array $uids an array of user ids to filter by
3031    * @return bool true on success
3032    */
3033
3034   public function admin_getBannedUsers($uids = null) {
3035     return $this->call_method(
3036       'admin.getBannedUsers',
3037       array('uids' => $uids ? json_encode($uids) : null));
3038   }
3039
3040
3041   /* UTILITY FUNCTIONS */
3042
3043   /**
3044    * Calls the specified normal POST method with the specified parameters.
3045    *
3046    * @param string $method  Name of the Facebook method to invoke
3047    * @param array $params   A map of param names => param values
3048    *
3049    * @return mixed  Result of method call; this returns a reference to support
3050    *                'delayed returns' when in a batch context.
3051    *     See: http://wiki.developers.facebook.com/index.php/Using_batching_API
3052    */
3053   public function &call_method($method, $params = array()) {
3054     if ($this->format) {
3055       $params['format'] = $this->format;
3056     }
3057     if (!$this->pending_batch()) {
3058       if ($this->call_as_apikey) {
3059         $params['call_as_apikey'] = $this->call_as_apikey;
3060       }
3061       $data = $this->post_request($method, $params);
3062       $this->rawData = $data;
3063       $result = $this->convert_result($data, $method, $params);
3064       if (is_array($result) && isset($result['error_code'])) {
3065         throw new FacebookRestClientException($result['error_msg'],
3066                                               $result['error_code']);
3067       }
3068     }
3069     else {
3070       $result = null;
3071       $batch_item = array('m' => $method, 'p' => $params, 'r' => & $result);
3072       $this->batch_queue[] = $batch_item;
3073     }
3074
3075     return $result;
3076   }
3077
3078   protected function convert_result($data, $method, $params) {
3079     $is_xml = (empty($params['format']) ||
3080                strtolower($params['format']) != 'json');
3081     return ($is_xml) ? $this->convert_xml_to_result($data, $method, $params)
3082                      : json_decode($data, true);
3083   }
3084
3085   /**
3086    * Change the response format
3087    *
3088    * @param string $format The response format (json, xml)
3089    */
3090   public function setFormat($format) {
3091     $this->format = $format;
3092     return $this;
3093   }
3094
3095   /**
3096    * get the current response serialization format
3097    *
3098    * @return string 'xml', 'json', or null (which means 'xml')
3099    */
3100   public function getFormat() {
3101     return $this->format;
3102   }
3103
3104   /**
3105    * Returns the raw JSON or XML output returned by the server in the most
3106    * recent API call.
3107    *
3108    * @return string
3109    */
3110    public function getRawData() {
3111      return $this->rawData;
3112    }
3113
3114   /**
3115    * Calls the specified file-upload POST method with the specified parameters
3116    *
3117    * @param string $method Name of the Facebook method to invoke
3118    * @param array  $params A map of param names => param values
3119    * @param string $file   A path to the file to upload (required)
3120    *
3121    * @return array A dictionary representing the response.
3122    */
3123   public function call_upload_method($method, $params, $file, $server_addr = null) {
3124     if (!$this->pending_batch()) {
3125       if (!file_exists($file)) {
3126         $code =
3127           FacebookAPIErrorCodes::API_EC_PARAM;
3128         $description = FacebookAPIErrorCodes::$api_error_descriptions[$code];
3129         throw new FacebookRestClientException($description, $code);
3130       }
3131
3132       if ($this->format) {
3133         $params['format'] = $this->format;
3134       }
3135       $data = $this->post_upload_request($method,
3136                                          $params,
3137                                          $file,
3138                                          $server_addr);
3139       $result = $this->convert_result($data, $method, $params);
3140
3141       if (is_array($result) && isset($result['error_code'])) {
3142         throw new FacebookRestClientException($result['error_msg'],
3143                                               $result['error_code']);
3144       }
3145     }
3146     else {
3147       $code =
3148         FacebookAPIErrorCodes::API_EC_BATCH_METHOD_NOT_ALLOWED_IN_BATCH_MODE;
3149       $description = FacebookAPIErrorCodes::$api_error_descriptions[$code];
3150       throw new FacebookRestClientException($description, $code);
3151     }
3152
3153     return $result;
3154   }
3155
3156   protected function convert_xml_to_result($xml, $method, $params) {
3157     $sxml = simplexml_load_string($xml);
3158     $result = self::convert_simplexml_to_array($sxml);
3159
3160     if (!empty($GLOBALS['facebook_config']['debug'])) {
3161       // output the raw xml and its corresponding php object, for debugging:
3162       print '<div style="margin: 10px 30px; padding: 5px; border: 2px solid black; background: gray; color: white; font-size: 12px; font-weight: bold;">';
3163       $this->cur_id++;
3164       print $this->cur_id . ': Called ' . $method . ', show ' .
3165             '<a href=# onclick="return toggleDisplay(' . $this->cur_id . ', \'params\');">Params</a> | '.
3166             '<a href=# onclick="return toggleDisplay(' . $this->cur_id . ', \'xml\');">XML</a> | '.
3167             '<a href=# onclick="return toggleDisplay(' . $this->cur_id . ', \'sxml\');">SXML</a> | '.
3168             '<a href=# onclick="return toggleDisplay(' . $this->cur_id . ', \'php\');">PHP</a>';
3169       print '<pre id="params'.$this->cur_id.'" style="display: none; overflow: auto;">'.print_r($params, true).'</pre>';
3170       print '<pre id="xml'.$this->cur_id.'" style="display: none; overflow: auto;">'.htmlspecialchars($xml).'</pre>';
3171       print '<pre id="php'.$this->cur_id.'" style="display: none; overflow: auto;">'.print_r($result, true).'</pre>';
3172       print '<pre id="sxml'.$this->cur_id.'" style="display: none; overflow: auto;">'.print_r($sxml, true).'</pre>';
3173       print '</div>';
3174     }
3175     return $result;
3176   }
3177
3178   protected function finalize_params($method, $params) {
3179     list($get, $post) = $this->add_standard_params($method, $params);
3180     // we need to do this before signing the params
3181     $this->convert_array_values_to_json($post);
3182     $post['sig'] = Facebook::generate_sig(array_merge($get, $post),
3183                                           $this->secret);
3184     return array($get, $post);
3185   }
3186
3187   private function convert_array_values_to_json(&$params) {
3188     foreach ($params as $key => &$val) {
3189       if (is_array($val)) {
3190         $val = json_encode($val);
3191       }
3192     }
3193   }
3194
3195   /**
3196    * Add the generally required params to our request.
3197    * Params method, api_key, and v should be sent over as get.
3198    */
3199   private function add_standard_params($method, $params) {
3200     $post = $params;
3201     $get = array();
3202     if ($this->call_as_apikey) {
3203       $get['call_as_apikey'] = $this->call_as_apikey;
3204     }
3205     if ($this->using_session_secret) {
3206       $get['ss'] = '1';
3207     }
3208
3209     $get['method'] = $method;
3210     $get['session_key'] = $this->session_key;
3211     $get['api_key'] = $this->api_key;
3212     $post['call_id'] = microtime(true);
3213     if ($post['call_id'] <= $this->last_call_id) {
3214       $post['call_id'] = $this->last_call_id + 0.001;
3215     }
3216     $this->last_call_id = $post['call_id'];
3217     if (isset($post['v'])) {
3218       $get['v'] = $post['v'];
3219       unset($post['v']);
3220     } else {
3221       $get['v'] = '1.0';
3222     }
3223     if (isset($this->use_ssl_resources)) {
3224       $post['return_ssl_resources'] = (bool) $this->use_ssl_resources;
3225     }
3226     return array($get, $post);
3227   }
3228
3229   private function create_url_string($params) {
3230     $post_params = array();
3231     foreach ($params as $key => &$val) {
3232       $post_params[] = $key.'='.urlencode($val);
3233     }
3234     return implode('&', $post_params);
3235   }
3236
3237   private function run_multipart_http_transaction($method, $params, $file, $server_addr) {
3238
3239     // the format of this message is specified in RFC1867/RFC1341.
3240     // we add twenty pseudo-random digits to the end of the boundary string.
3241     $boundary = '--------------------------FbMuLtIpArT' .
3242                 sprintf("%010d", mt_rand()) .
3243                 sprintf("%010d", mt_rand());
3244     $content_type = 'multipart/form-data; boundary=' . $boundary;
3245     // within the message, we prepend two extra hyphens.
3246     $delimiter = '--' . $boundary;
3247     $close_delimiter = $delimiter . '--';
3248     $content_lines = array();
3249     foreach ($params as $key => &$val) {
3250       $content_lines[] = $delimiter;
3251       $content_lines[] = 'Content-Disposition: form-data; name="' . $key . '"';
3252       $content_lines[] = '';
3253       $content_lines[] = $val;
3254     }
3255     // now add the file data
3256     $content_lines[] = $delimiter;
3257     $content_lines[] =
3258       'Content-Disposition: form-data; filename="' . $file . '"';
3259     $content_lines[] = 'Content-Type: application/octet-stream';
3260     $content_lines[] = '';
3261     $content_lines[] = file_get_contents($file);
3262     $content_lines[] = $close_delimiter;
3263     $content_lines[] = '';
3264     $content = implode("\r\n", $content_lines);
3265     return $this->run_http_post_transaction($content_type, $content, $server_addr);
3266   }
3267
3268   public function post_request($method, $params) {
3269     list($get, $post) = $this->finalize_params($method, $params);
3270     $post_string = $this->create_url_string($post);
3271     $get_string = $this->create_url_string($get);
3272     $url_with_get = $this->server_addr . '?' . $get_string;
3273     if ($this->use_curl_if_available && function_exists('curl_init')) {
3274       $useragent = 'Facebook API PHP5 Client 1.1 (curl) ' . phpversion();
3275       $ch = curl_init();
3276       curl_setopt($ch, CURLOPT_URL, $url_with_get);
3277       curl_setopt($ch, CURLOPT_POSTFIELDS, $post_string);
3278       curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
3279       curl_setopt($ch, CURLOPT_USERAGENT, $useragent);
3280       curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
3281       curl_setopt($ch, CURLOPT_TIMEOUT, 30);
3282       $result = $this->curl_exec($ch);
3283       curl_close($ch);
3284     } else {
3285       $content_type = 'application/x-www-form-urlencoded';
3286       $content = $post_string;
3287       $result = $this->run_http_post_transaction($content_type,
3288                                                  $content,
3289                                                  $url_with_get);
3290     }
3291     return $result;
3292   }
3293
3294   /**
3295    * execute a curl transaction -- this exists mostly so subclasses can add
3296    * extra options and/or process the response, if they wish.
3297    *
3298    * @param resource $ch a curl handle
3299    */
3300   protected function curl_exec($ch) {
3301       $result = curl_exec($ch);
3302       return $result;
3303   }
3304
3305   protected function post_upload_request($method, $params, $file, $server_addr = null) {
3306     $server_addr = $server_addr ? $server_addr : $this->server_addr;
3307     list($get, $post) = $this->finalize_params($method, $params);
3308     $get_string = $this->create_url_string($get);
3309     $url_with_get = $server_addr . '?' . $get_string;
3310     if ($this->use_curl_if_available && function_exists('curl_init')) {
3311       // prepending '@' causes cURL to upload the file; the key is ignored.
3312       $post['_file'] = '@' . $file;
3313       $useragent = 'Facebook API PHP5 Client 1.1 (curl) ' . phpversion();
3314       $ch = curl_init();
3315       curl_setopt($ch, CURLOPT_URL, $url_with_get);
3316       // this has to come before the POSTFIELDS set!
3317       curl_setopt($ch, CURLOPT_POST, 1);
3318       // passing an array gets curl to use the multipart/form-data content type
3319       curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
3320       curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
3321       curl_setopt($ch, CURLOPT_USERAGENT, $useragent);
3322       $result = $this->curl_exec($ch);
3323       curl_close($ch);
3324     } else {
3325       $result = $this->run_multipart_http_transaction($method, $post,
3326                                                       $file, $url_with_get);
3327     }
3328     return $result;
3329   }
3330
3331   private function run_http_post_transaction($content_type, $content, $server_addr) {
3332
3333     $user_agent = 'Facebook API PHP5 Client 1.1 (non-curl) ' . phpversion();
3334     $content_length = strlen($content);
3335     $context =
3336       array('http' =>
3337               array('method' => 'POST',
3338                     'user_agent' => $user_agent,
3339                     'header' => 'Content-Type: ' . $content_type . "\r\n" .
3340                                 'Content-Length: ' . $content_length,
3341                     'content' => $content));
3342     $context_id = stream_context_create($context);
3343     $sock = fopen($server_addr, 'r', false, $context_id);
3344
3345     $result = '';
3346     if ($sock) {
3347       while (!feof($sock)) {
3348         $result .= fgets($sock, 4096);
3349       }
3350       fclose($sock);
3351     }
3352     return $result;
3353   }
3354
3355   public static function convert_simplexml_to_array($sxml) {
3356     $arr = array();
3357     if ($sxml) {
3358       foreach ($sxml as $k => $v) {
3359         if ($sxml['list']) {
3360           $arr[] = self::convert_simplexml_to_array($v);
3361         } else {
3362           $arr[$k] = self::convert_simplexml_to_array($v);
3363         }
3364       }
3365     }
3366     if (sizeof($arr) > 0) {
3367       return $arr;
3368     } else {
3369       return (string)$sxml;
3370     }
3371   }
3372
3373   protected function get_uid($uid) {
3374     return $uid ? $uid : $this->user;
3375   }
3376 }
3377
3378
3379 class FacebookRestClientException extends Exception {
3380 }
3381
3382 // Supporting methods and values------
3383
3384 /**
3385  * Error codes and descriptions for the Facebook API.
3386  */
3387
3388 class FacebookAPIErrorCodes {
3389
3390   const API_EC_SUCCESS = 0;
3391
3392   /*
3393    * GENERAL ERRORS
3394    */
3395   const API_EC_UNKNOWN = 1;
3396   const API_EC_SERVICE = 2;
3397   const API_EC_METHOD = 3;
3398   const API_EC_TOO_MANY_CALLS = 4;
3399   const API_EC_BAD_IP = 5;
3400   const API_EC_HOST_API = 6;
3401   const API_EC_HOST_UP = 7;
3402   const API_EC_SECURE = 8;
3403   const API_EC_RATE = 9;
3404   const API_EC_PERMISSION_DENIED = 10;
3405   const API_EC_DEPRECATED = 11;
3406   const API_EC_VERSION = 12;
3407   const API_EC_INTERNAL_FQL_ERROR = 13;
3408   const API_EC_HOST_PUP = 14;
3409   const API_EC_SESSION_SECRET_NOT_ALLOWED = 15;
3410   const API_EC_HOST_READONLY = 16;
3411
3412   /*
3413    * PARAMETER ERRORS
3414    */
3415   const API_EC_PARAM = 100;
3416   const API_EC_PARAM_API_KEY = 101;
3417   const API_EC_PARAM_SESSION_KEY = 102;
3418   const API_EC_PARAM_CALL_ID = 103;
3419   const API_EC_PARAM_SIGNATURE = 104;
3420   const API_EC_PARAM_TOO_MANY = 105;
3421   const API_EC_PARAM_USER_ID = 110;
3422   const API_EC_PARAM_USER_FIELD = 111;
3423   const API_EC_PARAM_SOCIAL_FIELD = 112;
3424   const API_EC_PARAM_EMAIL = 113;
3425   const API_EC_PARAM_USER_ID_LIST = 114;
3426   const API_EC_PARAM_FIELD_LIST = 115;
3427   const API_EC_PARAM_ALBUM_ID = 120;
3428   const API_EC_PARAM_PHOTO_ID = 121;
3429   const API_EC_PARAM_FEED_PRIORITY = 130;
3430   const API_EC_PARAM_CATEGORY = 140;
3431   const API_EC_PARAM_SUBCATEGORY = 141;
3432   const API_EC_PARAM_TITLE = 142;
3433   const API_EC_PARAM_DESCRIPTION = 143;
3434   const API_EC_PARAM_BAD_JSON = 144;
3435   const API_EC_PARAM_BAD_EID = 150;
3436   const API_EC_PARAM_UNKNOWN_CITY = 151;
3437   const API_EC_PARAM_BAD_PAGE_TYPE = 152;
3438   const API_EC_PARAM_BAD_LOCALE = 170;
3439   const API_EC_PARAM_BLOCKED_NOTIFICATION = 180;
3440
3441   /*
3442    * USER PERMISSIONS ERRORS
3443    */
3444   const API_EC_PERMISSION = 200;
3445   const API_EC_PERMISSION_USER = 210;
3446   const API_EC_PERMISSION_NO_DEVELOPERS = 211;
3447   const API_EC_PERMISSION_OFFLINE_ACCESS = 212;
3448   const API_EC_PERMISSION_ALBUM = 220;
3449   const API_EC_PERMISSION_PHOTO = 221;
3450   const API_EC_PERMISSION_MESSAGE = 230;
3451   const API_EC_PERMISSION_OTHER_USER = 240;
3452   const API_EC_PERMISSION_STATUS_UPDATE = 250;
3453   const API_EC_PERMISSION_PHOTO_UPLOAD = 260;
3454   const API_EC_PERMISSION_VIDEO_UPLOAD = 261;
3455   const API_EC_PERMISSION_SMS = 270;
3456   const API_EC_PERMISSION_CREATE_LISTING = 280;
3457   const API_EC_PERMISSION_CREATE_NOTE = 281;
3458   const API_EC_PERMISSION_SHARE_ITEM = 282;
3459   const API_EC_PERMISSION_EVENT = 290;
3460   const API_EC_PERMISSION_LARGE_FBML_TEMPLATE = 291;
3461   const API_EC_PERMISSION_LIVEMESSAGE = 292;
3462   const API_EC_PERMISSION_CREATE_EVENT = 296;
3463   const API_EC_PERMISSION_RSVP_EVENT = 299;
3464
3465   /*
3466    * DATA EDIT ERRORS
3467    */
3468   const API_EC_EDIT = 300;
3469   const API_EC_EDIT_USER_DATA = 310;
3470   const API_EC_EDIT_PHOTO = 320;
3471   const API_EC_EDIT_ALBUM_SIZE = 321;
3472   const API_EC_EDIT_PHOTO_TAG_SUBJECT = 322;
3473   const API_EC_EDIT_PHOTO_TAG_PHOTO = 323;
3474   const API_EC_EDIT_PHOTO_FILE = 324;
3475   const API_EC_EDIT_PHOTO_PENDING_LIMIT = 325;
3476   const API_EC_EDIT_PHOTO_TAG_LIMIT = 326;
3477   const API_EC_EDIT_ALBUM_REORDER_PHOTO_NOT_IN_ALBUM = 327;
3478   const API_EC_EDIT_ALBUM_REORDER_TOO_FEW_PHOTOS = 328;
3479
3480   const API_EC_MALFORMED_MARKUP = 329;
3481   const API_EC_EDIT_MARKUP = 330;
3482
3483   const API_EC_EDIT_FEED_TOO_MANY_USER_CALLS = 340;
3484   const API_EC_EDIT_FEED_TOO_MANY_USER_ACTION_CALLS = 341;
3485   const API_EC_EDIT_FEED_TITLE_LINK = 342;
3486   const API_EC_EDIT_FEED_TITLE_LENGTH = 343;
3487   const API_EC_EDIT_FEED_TITLE_NAME = 344;
3488   const API_EC_EDIT_FEED_TITLE_BLANK = 345;
3489   const API_EC_EDIT_FEED_BODY_LENGTH = 346;
3490   const API_EC_EDIT_FEED_PHOTO_SRC = 347;
3491   const API_EC_EDIT_FEED_PHOTO_LINK = 348;
3492
3493   const API_EC_EDIT_VIDEO_SIZE = 350;
3494   const API_EC_EDIT_VIDEO_INVALID_FILE = 351;
3495   const API_EC_EDIT_VIDEO_INVALID_TYPE = 352;
3496   const API_EC_EDIT_VIDEO_FILE = 353;
3497
3498   const API_EC_EDIT_FEED_TITLE_ARRAY = 360;
3499   const API_EC_EDIT_FEED_TITLE_PARAMS = 361;
3500   const API_EC_EDIT_FEED_BODY_ARRAY = 362;
3501   const API_EC_EDIT_FEED_BODY_PARAMS = 363;
3502   const API_EC_EDIT_FEED_PHOTO = 364;
3503   const API_EC_EDIT_FEED_TEMPLATE = 365;
3504   const API_EC_EDIT_FEED_TARGET = 366;
3505   const API_EC_EDIT_FEED_MARKUP = 367;
3506
3507   /**
3508    * SESSION ERRORS
3509    */
3510   const API_EC_SESSION_TIMED_OUT = 450;
3511   const API_EC_SESSION_METHOD = 451;
3512   const API_EC_SESSION_INVALID = 452;
3513   const API_EC_SESSION_REQUIRED = 453;
3514   const API_EC_SESSION_REQUIRED_FOR_SECRET = 454;
3515   const API_EC_SESSION_CANNOT_USE_SESSION_SECRET = 455;
3516
3517
3518   /**
3519    * FQL ERRORS
3520    */
3521   const FQL_EC_UNKNOWN_ERROR = 600;
3522   const FQL_EC_PARSER = 601; // backwards compatibility
3523   const FQL_EC_PARSER_ERROR = 601;
3524   const FQL_EC_UNKNOWN_FIELD = 602;
3525   const FQL_EC_UNKNOWN_TABLE = 603;
3526   const FQL_EC_NOT_INDEXABLE = 604; // backwards compatibility
3527   const FQL_EC_NO_INDEX = 604;
3528   const FQL_EC_UNKNOWN_FUNCTION = 605;
3529   const FQL_EC_INVALID_PARAM = 606;
3530   const FQL_EC_INVALID_FIELD = 607;
3531   const FQL_EC_INVALID_SESSION = 608;
3532   const FQL_EC_UNSUPPORTED_APP_TYPE = 609;
3533   const FQL_EC_SESSION_SECRET_NOT_ALLOWED = 610;
3534   const FQL_EC_DEPRECATED_TABLE = 611;
3535   const FQL_EC_EXTENDED_PERMISSION = 612;
3536   const FQL_EC_RATE_LIMIT_EXCEEDED = 613;
3537   const FQL_EC_UNRESOLVED_DEPENDENCY = 614;
3538   const FQL_EC_INVALID_SEARCH = 615;
3539   const FQL_EC_CONTAINS_ERROR = 616;
3540
3541   const API_EC_REF_SET_FAILED = 700;
3542
3543   /**
3544    * DATA STORE API ERRORS
3545    */
3546   const API_EC_DATA_UNKNOWN_ERROR = 800;
3547   const API_EC_DATA_INVALID_OPERATION = 801;
3548   const API_EC_DATA_QUOTA_EXCEEDED = 802;
3549   const API_EC_DATA_OBJECT_NOT_FOUND = 803;
3550   const API_EC_DATA_OBJECT_ALREADY_EXISTS = 804;
3551   const API_EC_DATA_DATABASE_ERROR = 805;
3552   const API_EC_DATA_CREATE_TEMPLATE_ERROR = 806;
3553   const API_EC_DATA_TEMPLATE_EXISTS_ERROR = 807;
3554   const API_EC_DATA_TEMPLATE_HANDLE_TOO_LONG = 808;
3555   const API_EC_DATA_TEMPLATE_HANDLE_ALREADY_IN_USE = 809;
3556   const API_EC_DATA_TOO_MANY_TEMPLATE_BUNDLES = 810;
3557   const API_EC_DATA_MALFORMED_ACTION_LINK = 811;
3558   const API_EC_DATA_TEMPLATE_USES_RESERVED_TOKEN = 812;
3559
3560   /*
3561    * APPLICATION INFO ERRORS
3562    */
3563   const API_EC_NO_SUCH_APP = 900;
3564
3565   /*
3566    * BATCH ERRORS
3567    */
3568   const API_EC_BATCH_TOO_MANY_ITEMS = 950;
3569   const API_EC_BATCH_ALREADY_STARTED = 951;
3570   const API_EC_BATCH_NOT_STARTED = 952;
3571   const API_EC_BATCH_METHOD_NOT_ALLOWED_IN_BATCH_MODE = 953;
3572
3573   /*
3574    * EVENT API ERRORS
3575    */
3576   const API_EC_EVENT_INVALID_TIME = 1000;
3577   const API_EC_EVENT_NAME_LOCKED  = 1001;
3578
3579   /*
3580    * INFO BOX ERRORS
3581    */
3582   const API_EC_INFO_NO_INFORMATION = 1050;
3583   const API_EC_INFO_SET_FAILED = 1051;
3584
3585   /*
3586    * LIVEMESSAGE API ERRORS
3587    */
3588   const API_EC_LIVEMESSAGE_SEND_FAILED = 1100;
3589   const API_EC_LIVEMESSAGE_EVENT_NAME_TOO_LONG = 1101;
3590   const API_EC_LIVEMESSAGE_MESSAGE_TOO_LONG = 1102;
3591
3592   /*
3593    * PAYMENTS API ERRORS
3594    */
3595   const API_EC_PAYMENTS_UNKNOWN = 1150;
3596   const API_EC_PAYMENTS_APP_INVALID = 1151;
3597   const API_EC_PAYMENTS_DATABASE = 1152;
3598   const API_EC_PAYMENTS_PERMISSION_DENIED = 1153;
3599   const API_EC_PAYMENTS_APP_NO_RESPONSE = 1154;
3600   const API_EC_PAYMENTS_APP_ERROR_RESPONSE = 1155;
3601   const API_EC_PAYMENTS_INVALID_ORDER = 1156;
3602   const API_EC_PAYMENTS_INVALID_PARAM = 1157;
3603   const API_EC_PAYMENTS_INVALID_OPERATION = 1158;
3604   const API_EC_PAYMENTS_PAYMENT_FAILED = 1159;
3605   const API_EC_PAYMENTS_DISABLED = 1160;
3606
3607   /*
3608    * CONNECT SESSION ERRORS
3609    */
3610   const API_EC_CONNECT_FEED_DISABLED = 1300;
3611
3612   /*
3613    * Platform tag bundles errors
3614    */
3615   const API_EC_TAG_BUNDLE_QUOTA = 1400;
3616
3617   /*
3618    * SHARE
3619    */
3620   const API_EC_SHARE_BAD_URL = 1500;
3621
3622   /*
3623    * NOTES
3624    */
3625   const API_EC_NOTE_CANNOT_MODIFY = 1600;
3626
3627   /*
3628    * COMMENTS
3629    */
3630   const API_EC_COMMENTS_UNKNOWN = 1700;
3631   const API_EC_COMMENTS_POST_TOO_LONG = 1701;
3632   const API_EC_COMMENTS_DB_DOWN = 1702;
3633   const API_EC_COMMENTS_INVALID_XID = 1703;
3634   const API_EC_COMMENTS_INVALID_UID = 1704;
3635   const API_EC_COMMENTS_INVALID_POST = 1705;
3636   const API_EC_COMMENTS_INVALID_REMOVE = 1706;
3637
3638   /*
3639    * GIFTS
3640    */
3641   const API_EC_GIFTS_UNKNOWN = 1900;
3642
3643   /*
3644    * APPLICATION MORATORIUM ERRORS
3645    */
3646   const API_EC_DISABLED_ALL = 2000;
3647   const API_EC_DISABLED_STATUS = 2001;
3648   const API_EC_DISABLED_FEED_STORIES = 2002;
3649   const API_EC_DISABLED_NOTIFICATIONS = 2003;
3650   const API_EC_DISABLED_REQUESTS = 2004;
3651   const API_EC_DISABLED_EMAIL = 2005;
3652
3653   /**
3654    * This array is no longer maintained; to view the description of an error
3655    * code, please look at the message element of the API response or visit
3656    * the developer wiki at http://wiki.developers.facebook.com/.
3657    */
3658   public static $api_error_descriptions = array(
3659       self::API_EC_SUCCESS           => 'Success',
3660       self::API_EC_UNKNOWN           => 'An unknown error occurred',
3661       self::API_EC_SERVICE           => 'Service temporarily unavailable',
3662       self::API_EC_METHOD            => 'Unknown method',
3663       self::API_EC_TOO_MANY_CALLS    => 'Application request limit reached',
3664       self::API_EC_BAD_IP            => 'Unauthorized source IP address',
3665       self::API_EC_PARAM             => 'Invalid parameter',
3666       self::API_EC_PARAM_API_KEY     => 'Invalid API key',
3667       self::API_EC_PARAM_SESSION_KEY => 'Session key invalid or no longer valid',
3668       self::API_EC_PARAM_CALL_ID     => 'Call_id must be greater than previous',
3669       self::API_EC_PARAM_SIGNATURE   => 'Incorrect signature',
3670       self::API_EC_PARAM_USER_ID     => 'Invalid user id',
3671       self::API_EC_PARAM_USER_FIELD  => 'Invalid user info field',
3672       self::API_EC_PARAM_SOCIAL_FIELD => 'Invalid user field',
3673       self::API_EC_PARAM_USER_ID_LIST => 'Invalid user id list',
3674       self::API_EC_PARAM_FIELD_LIST => 'Invalid field list',
3675       self::API_EC_PARAM_ALBUM_ID    => 'Invalid album id',
3676       self::API_EC_PARAM_BAD_EID     => 'Invalid eid',
3677       self::API_EC_PARAM_UNKNOWN_CITY => 'Unknown city',
3678       self::API_EC_PERMISSION        => 'Permissions error',
3679       self::API_EC_PERMISSION_USER   => 'User not visible',
3680       self::API_EC_PERMISSION_NO_DEVELOPERS  => 'Application has no developers',
3681       self::API_EC_PERMISSION_ALBUM  => 'Album not visible',
3682       self::API_EC_PERMISSION_PHOTO  => 'Photo not visible',
3683       self::API_EC_PERMISSION_EVENT  => 'Creating and modifying events required the extended permission create_event',
3684       self::API_EC_PERMISSION_RSVP_EVENT => 'RSVPing to events required the extended permission rsvp_event',
3685       self::API_EC_EDIT_ALBUM_SIZE   => 'Album is full',
3686       self::FQL_EC_PARSER            => 'FQL: Parser Error',
3687       self::FQL_EC_UNKNOWN_FIELD     => 'FQL: Unknown Field',
3688       self::FQL_EC_UNKNOWN_TABLE     => 'FQL: Unknown Table',
3689       self::FQL_EC_NOT_INDEXABLE     => 'FQL: Statement not indexable',
3690       self::FQL_EC_UNKNOWN_FUNCTION  => 'FQL: Attempted to call unknown function',
3691       self::FQL_EC_INVALID_PARAM     => 'FQL: Invalid parameter passed in',
3692       self::API_EC_DATA_UNKNOWN_ERROR => 'Unknown data store API error',
3693       self::API_EC_DATA_INVALID_OPERATION => 'Invalid operation',
3694       self::API_EC_DATA_QUOTA_EXCEEDED => 'Data store allowable quota was exceeded',
3695       self::API_EC_DATA_OBJECT_NOT_FOUND => 'Specified object cannot be found',
3696       self::API_EC_DATA_OBJECT_ALREADY_EXISTS => 'Specified object already exists',
3697       self::API_EC_DATA_DATABASE_ERROR => 'A database error occurred. Please try again',
3698       self::API_EC_BATCH_ALREADY_STARTED => 'begin_batch already called, please make sure to call end_batch first',
3699       self::API_EC_BATCH_NOT_STARTED => 'end_batch called before begin_batch',
3700       self::API_EC_BATCH_METHOD_NOT_ALLOWED_IN_BATCH_MODE => 'This method is not allowed in batch mode'
3701   );
3702 }