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