ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/repos/facebook/trunk/facebookapi_php5_restlib.php
Revision: 950
Committed: 2007-09-29T14:02:03-07:00 (17 years, 8 months ago) by douglas
File size: 23995 byte(s)
Log Message:
Manually merged with 2007-09-25 because svn didn't want to do it usefully...

File Contents

# Content
1 <?php
2 # vim: expandtab shiftwidth=2 tabstop=2
3 #
4 # Modified to use JSON when $json is set to true.
5 #
6 # Douglas Thrift
7 #
8 # $Id$
9 //
10 // +---------------------------------------------------------------------------+
11 // | Facebook Platform PHP5 client |
12 // +---------------------------------------------------------------------------+
13 // | Copyright (c) 2007 Facebook, Inc. |
14 // | All rights reserved. |
15 // | |
16 // | Redistribution and use in source and binary forms, with or without |
17 // | modification, are permitted provided that the following conditions |
18 // | are met: |
19 // | |
20 // | 1. Redistributions of source code must retain the above copyright |
21 // | notice, this list of conditions and the following disclaimer. |
22 // | 2. Redistributions in binary form must reproduce the above copyright |
23 // | notice, this list of conditions and the following disclaimer in the |
24 // | documentation and/or other materials provided with the distribution. |
25 // | |
26 // | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
27 // | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
28 // | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
29 // | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
30 // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
31 // | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
32 // | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
33 // | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
34 // | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
35 // | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
36 // +---------------------------------------------------------------------------+
37 // | For help with this library, contact developers-help@facebook.com |
38 // +---------------------------------------------------------------------------+
39 //
40
41 class FacebookRestClient {
42 public $secret;
43 public $session_key;
44 public $api_key;
45 public $friends_list; // to save making the friends.get api call, this will get prepopulated on canvas pages
46 public $added; // to save making the users.isAppAdded api call, this will get prepopulated on canvas pages
47 public $json;
48
49 /**
50 * Create the client.
51 * @param string $session_key if you haven't gotten a session key yet, leave
52 * this as null and then set it later by just
53 * directly accessing the $session_key member
54 * variable.
55 */
56 public function __construct($api_key, $secret, $session_key=null) {
57 $this->secret = $secret;
58 $this->session_key = $session_key;
59 $this->api_key = $api_key;
60 $this->last_call_id = 0;
61 $this->server_addr = Facebook::get_facebook_url('api') . '/restserver.php';
62 if ($GLOBALS['facebook_config']['debug']) {
63 $this->cur_id = 0;
64 ?>
65 <script type="text/javascript">
66 var types = ['params', 'xml', 'php', 'sxml'];
67 function toggleDisplay(id, type) {
68 for each (var t in types) {
69 if (t != type || document.getElementById(t + id).style.display == 'block') {
70 document.getElementById(t + id).style.display = 'none';
71 } else {
72 document.getElementById(t + id).style.display = 'block';
73 }
74 }
75 return false;
76 }
77 </script>
78 <?php
79 }
80 }
81
82 /**
83 * Returns the session information available after current user logs in.
84 * @param string $auth_token the token returned by auth_createToken or
85 * passed back to your callback_url.
86 * @return assoc array containing session_key, uid
87 */
88 public function auth_getSession($auth_token) {
89 $result = $this->call_method('facebook.auth.getSession', array('auth_token'=>$auth_token));
90 $this->session_key = $result['session_key'];
91 if (isset($result['secret']) && $result['secret']) {
92 // desktop apps have a special secret
93 $this->secret = $result['secret'];
94 }
95 return $result;
96 }
97
98 /**
99 * Returns events according to the filters specified.
100 * @param int $uid Optional: User associated with events.
101 * A null parameter will default to the session user.
102 * @param array $eids Optional: Filter by these event ids.
103 * A null parameter will get all events for the user.
104 * @param int $start_time Optional: Filter with this UTC as lower bound.
105 * A null or zero parameter indicates no lower bound.
106 * @param int $end_time Optional: Filter with this UTC as upper bound.
107 * A null or zero parameter indicates no upper bound.
108 * @param string $rsvp_status Optional: Only show events where the given uid
109 * has this rsvp status. This only works if you have specified a value for
110 * $uid. Values are as in events.getMembers. Null indicates to ignore
111 * rsvp status when filtering.
112 * @return array of events
113 */
114 public function events_get($uid, $eids, $start_time, $end_time, $rsvp_status) {
115 return $this->call_method('facebook.events.get',
116 array(
117 'uid' => $uid,
118 'eids' => $eids,
119 'start_time' => $start_time,
120 'end_time' => $end_time,
121 'rsvp_status' => $rsvp_status));
122 }
123
124 /**
125 * Returns membership list data associated with an event
126 * @param int $eid : event id
127 * @return assoc array of four membership lists, with keys 'attending',
128 * 'unsure', 'declined', and 'not_replied'
129 */
130 public function events_getMembers($eid) {
131 return $this->call_method('facebook.events.getMembers',
132 array('eid' => $eid));
133 }
134
135 /**
136 * Makes an FQL query. This is a generalized way of accessing all the data
137 * in the API, as an alternative to most of the other method calls. More
138 * info at http://developers.facebook.com/documentation.php?v=1.0&doc=fql
139 * @param string $query the query to evaluate
140 * @return generalized array representing the results
141 */
142 public function fql_query($query) {
143 return $this->call_method('facebook.fql.query',
144 array('query' => $query));
145 }
146
147 public function feed_publishStoryToUser($title, $body,
148 $image_1=null, $image_1_link=null,
149 $image_2=null, $image_2_link=null,
150 $image_3=null, $image_3_link=null,
151 $image_4=null, $image_4_link=null) {
152 return $this->call_method('facebook.feed.publishStoryToUser',
153 array('title' => $title,
154 'body' => $body,
155 'image_1' => $image_1,
156 'image_1_link' => $image_1_link,
157 'image_2' => $image_2,
158 'image_2_link' => $image_2_link,
159 'image_3' => $image_3,
160 'image_3_link' => $image_3_link,
161 'image_4' => $image_4,
162 'image_4_link' => $image_4_link));
163 }
164
165 public function feed_publishActionOfUser($title, $body,
166 $image_1=null, $image_1_link=null,
167 $image_2=null, $image_2_link=null,
168 $image_3=null, $image_3_link=null,
169 $image_4=null, $image_4_link=null) {
170 return $this->call_method('facebook.feed.publishActionOfUser',
171 array('title' => $title,
172 'body' => $body,
173 'image_1' => $image_1,
174 'image_1_link' => $image_1_link,
175 'image_2' => $image_2,
176 'image_2_link' => $image_2_link,
177 'image_3' => $image_3,
178 'image_3_link' => $image_3_link,
179 'image_4' => $image_4,
180 'image_4_link' => $image_4_link));
181 }
182
183 /**
184 * Returns whether or not pairs of users are friends.
185 * Note that the Facebook friend relationship is symmetric.
186 * @param array $uids1: array of ids (id_1, id_2,...) of some length X
187 * @param array $uids2: array of ids (id_A, id_B,...) of SAME length X
188 * @return array of uid pairs with bool, true if pair are friends, e.g.
189 * array( 0 => array('uid1' => id_1, 'uid2' => id_A, 'are_friends' => 1),
190 * 1 => array('uid1' => id_2, 'uid2' => id_B, 'are_friends' => 0)
191 * ...)
192 */
193 public function friends_areFriends($uids1, $uids2) {
194 return $this->call_method('facebook.friends.areFriends',
195 array('uids1'=>$uids1, 'uids2'=>$uids2));
196 }
197
198 /**
199 * Returns the friends of the current session user.
200 * @return array of friends
201 */
202 public function friends_get() {
203 if (isset($this->friends_list)) {
204 return $this->friends_list;
205 }
206 return $this->call_method('facebook.friends.get', array());
207 }
208
209 /**
210 * Returns the friends of the session user, who are also users
211 * of the calling application.
212 * @return array of friends
213 */
214 public function friends_getAppUsers() {
215 return $this->call_method('facebook.friends.getAppUsers', array());
216 }
217
218 /**
219 * Returns groups according to the filters specified.
220 * @param int $uid Optional: User associated with groups.
221 * A null parameter will default to the session user.
222 * @param array $gids Optional: group ids to query.
223 * A null parameter will get all groups for the user.
224 * @return array of groups
225 */
226 public function groups_get($uid, $gids) {
227 return $this->call_method('facebook.groups.get',
228 array(
229 'uid' => $uid,
230 'gids' => $gids));
231 }
232
233 /**
234 * Returns the membership list of a group
235 * @param int $gid : Group id
236 * @return assoc array of four membership lists, with keys
237 * 'members', 'admins', 'officers', and 'not_replied'
238 */
239 public function groups_getMembers($gid) {
240 return $this->call_method('facebook.groups.getMembers',
241 array('gid' => $gid));
242 }
243
244 /**
245 * Returns the outstanding notifications for the session user.
246 * @return assoc array of
247 * notification count objects for 'messages', 'pokes' and 'shares',
248 * a uid list of 'friend_requests', a gid list of 'group_invites',
249 * and an eid list of 'event_invites'
250 */
251 public function notifications_get() {
252 return $this->call_method('facebook.notifications.get', array());
253 }
254
255 /**
256 * Sends an email notification to the specified user.
257 * @return string url which you should send the logged in user to to finalize the message.
258 */
259 public function notifications_send($to_ids, $notification, $email='') {
260 return $this->call_method('facebook.notifications.send',
261 array('to_ids' => $to_ids, 'notification' => $notification, 'email' => $email));
262 }
263
264 /**
265 * Sends a request to the specified user (e.g. "you have 1 event invitation")
266 * @param array $to_ids user ids to receive the request (must be friends with sender, capped at 10)
267 * @param string $type type of request, e.g. "event" (as in "You have an event invitation.")
268 * @param string $content fbml content of the request. really stripped down fbml - just
269 * text/names/links. also, use the special tag <fb:req-choice url="" label="" />
270 * to specify the buttons to be included.
271 * @param string $image url of an image to show beside the request
272 * @param bool $invite whether to call it an "invitation" or a "request"
273 * @return string url which you should send the logged in user to to finalize the message.
274 */
275 public function notifications_sendRequest($to_ids, $type, $content, $image, $invite) {
276 return $this->call_method('facebook.notifications.sendRequest',
277 array('to_ids' => $to_ids, 'type' => $type, 'content' => $content,
278 'image' => $image, 'invite' => $invite));
279 }
280
281 /**
282 * Returns photos according to the filters specified.
283 * @param int $subj_id Optional: Filter by uid of user tagged in the photos.
284 * @param int $aid Optional: Filter by an album, as returned by
285 * photos_getAlbums.
286 * @param array $pids Optional: Restrict to a list of pids
287 * Note that at least one of these parameters needs to be specified, or an
288 * error is returned.
289 * @return array of photo objects.
290 */
291 public function photos_get($subj_id, $aid, $pids) {
292 return $this->call_method('facebook.photos.get',
293 array('subj_id' => $subj_id, 'aid' => $aid, 'pids' => $pids));
294 }
295
296 /**
297 * Returns the albums created by the given user.
298 * @param int $uid Optional: the uid of the user whose albums you want.
299 * A null value will return the albums of the session user.
300 * @param array $aids Optional: a list of aids to restrict the query.
301 * Note that at least one of the (uid, aids) parameters must be specified.
302 * @returns an array of album objects.
303 */
304 public function photos_getAlbums($uid, $aids) {
305 return $this->call_method('facebook.photos.getAlbums',
306 array('uid' => $uid,
307 'aids' => $aids));
308 }
309
310 /**
311 * Returns the tags on all photos specified.
312 * @param string $pids : a list of pids to query
313 * @return array of photo tag objects, with include pid, subject uid,
314 * and two floating-point numbers (xcoord, ycoord) for tag pixel location
315 */
316 public function photos_getTags($pids) {
317 return $this->call_method('facebook.photos.getTags',
318 array('pids' => $pids));
319 }
320
321 /**
322 * Returns the requested info fields for the requested set of users
323 * @param array $uids an array of user ids
324 * @param array $fields an array of strings describing the info fields desired
325 * @return array of users
326 */
327 public function users_getInfo($uids, $fields) {
328 return $this->call_method('facebook.users.getInfo', array('uids' => $uids, 'fields' => $fields));
329 }
330
331 /**
332 * Returns the user corresponding to the current session object.
333 * @return integer uid
334 */
335 public function users_getLoggedInUser(){
336 return $this->call_method('facebook.users.getLoggedInUser', array());
337 }
338
339
340 /**
341 * Returns whether or not the user corresponding to the current session object has the app installed
342 * @return boolean
343 */
344 public function users_isAppAdded() {
345 if (isset($this->added)) {
346 return $this->added;
347 }
348 return $this->call_method('facebook.users.isAppAdded', array());
349 }
350
351 /**
352 * Sets the FBML for the profile of the user attached to this session
353 * @param string $markup The FBML that describes the profile presence of this app for the user
354 * @return array A list of strings describing any compile errors for the submitted FBML
355 */
356 public function profile_setFBML($markup, $uid = null) {
357 return $this->call_method('facebook.profile.setFBML', array('markup' => $markup, 'uid' => $uid));
358 }
359
360 public function profile_getFBML($uid) {
361 return $this->call_method('facebook.profile.getFBML', array('uid' => $uid));
362 }
363
364 public function fbml_refreshImgSrc($url) {
365 return $this->call_method('facebook.fbml.refreshImgSrc', array('url' => $url));
366 }
367
368 public function fbml_refreshRefUrl($url) {
369 return $this->call_method('facebook.fbml.refreshRefUrl', array('url' => $url));
370 }
371
372 public function fbml_setRefHandle($handle, $fbml) {
373 return $this->call_method('facebook.fbml.setRefHandle', array('handle' => $handle, 'fbml' => $fbml));
374 }
375
376 /* UTILITY FUNCTIONS */
377
378 public function call_method($method, $params) {
379 if ($this->json) {
380 $json = $this->post_request($method, $params);
381 # XXX: silly facebook with its invalid JSON
382 $valid = preg_match('/^[\[{].*[\]}]$/', $json);
383 $array = json_decode($valid ? $json : "[$json]", true);
384 $result = $valid ? $array : $array[0];
385 } else {
386 $xml = $this->post_request($method, $params);
387 $sxml = simplexml_load_string($xml);
388 $result = self::convert_simplexml_to_array($sxml);
389 if ($GLOBALS['facebook_config']['debug']) {
390 // output the raw xml and its corresponding php object, for debugging:
391 print '<div style="margin: 10px 30px; padding: 5px; border: 2px solid black; background: gray; color: white; font-size: 12px; font-weight: bold;">';
392 $this->cur_id++;
393 print $this->cur_id . ': Called ' . $method . ', show ' .
394 '<a href=# onclick="return toggleDisplay(' . $this->cur_id . ', \'params\');">Params</a> | '.
395 '<a href=# onclick="return toggleDisplay(' . $this->cur_id . ', \'xml\');">XML</a> | '.
396 '<a href=# onclick="return toggleDisplay(' . $this->cur_id . ', \'sxml\');">SXML</a> | '.
397 '<a href=# onclick="return toggleDisplay(' . $this->cur_id . ', \'php\');">PHP</a>';
398 print '<pre id="params'.$this->cur_id.'" style="display: none; overflow: auto;">'.print_r($params, true).'</pre>';
399 print '<pre id="xml'.$this->cur_id.'" style="display: none; overflow: auto;">'.htmlspecialchars($xml).'</pre>';
400 print '<pre id="php'.$this->cur_id.'" style="display: none; overflow: auto;">'.print_r($result, true).'</pre>';
401 print '<pre id="sxml'.$this->cur_id.'" style="display: none; overflow: auto;">'.print_r($sxml, true).'</pre>';
402 print '</div>';
403 }
404 }
405 if (is_array($result) && isset($result['error_code'])) {
406 throw new FacebookRestClientException($result['error_msg'], $result['error_code']);
407 }
408 return $result;
409 }
410
411 public function post_request($method, $params) {
412 $params['method'] = $method;
413 $params['session_key'] = $this->session_key;
414 $params['api_key'] = $this->api_key;
415 $params['call_id'] = microtime(true);
416 if ($params['call_id'] <= $this->last_call_id) {
417 $params['call_id'] = $this->last_call_id + 0.001;
418 }
419 $this->last_call_id = $params['call_id'];
420 if (!isset($params['v'])) {
421 $params['v'] = '1.0';
422 }
423 if ($this->json)
424 $params['format'] = 'JSON';
425 $post_params = array();
426 foreach ($params as $key => &$val) {
427 if (is_array($val)) $val = implode(',', $val);
428 $post_params[] = $key.'='.urlencode($val);
429 }
430 $post_params[] = 'sig='.Facebook::generate_sig($params, $this->secret);
431 $post_string = implode('&', $post_params);
432
433 if ($this->json) {
434 $result = file_get_contents($this->server_addr, false, stream_context_create(
435 array('http' =>
436 array('method' => 'POST',
437 'header' => 'Content-type: application/x-www-form-urlencoded'."\r\n".
438 'User-Agent: Facebook API PHP5 Client 1.1 (non-curl) '.phpversion()."\r\n".
439 'Content-length: ' . strlen($post_string),
440 'content' => $post_string))));
441 } elseif (function_exists('curl_init')) {
442 // Use CURL if installed...
443 $ch = curl_init();
444 curl_setopt($ch, CURLOPT_URL, $this->server_addr);
445 curl_setopt($ch, CURLOPT_POSTFIELDS, $post_string);
446 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
447 curl_setopt($ch, CURLOPT_USERAGENT, 'Facebook API PHP5 Client 1.1 (curl) ' . phpversion());
448 $result = curl_exec($ch);
449 curl_close($ch);
450 } else {
451 // Non-CURL based version...
452 $context =
453 array('http' =>
454 array('method' => 'POST',
455 'header' => 'Content-type: application/x-www-form-urlencoded'."\r\n".
456 'User-Agent: Facebook API PHP5 Client 1.1 (non-curl) '.phpversion()."\r\n".
457 'Content-length: ' . strlen($post_string),
458 'content' => $post_string));
459 $contextid=stream_context_create($context);
460 $sock=fopen($this->server_addr, 'r', false, $contextid);
461 if ($sock) {
462 $result='';
463 while (!feof($sock))
464 $result.=fgets($sock, 4096);
465
466 fclose($sock);
467 }
468 }
469 return $result;
470 }
471
472 public static function convert_simplexml_to_array($sxml) {
473 $arr = array();
474 if ($sxml) {
475 foreach ($sxml as $k => $v) {
476 if ($sxml['list']) {
477 $arr[] = self::convert_simplexml_to_array($v);
478 } else {
479 $arr[$k] = self::convert_simplexml_to_array($v);
480 }
481 }
482 }
483 if (sizeof($arr) > 0) {
484 return $arr;
485 } else {
486 return (string)$sxml;
487 }
488 }
489 }
490
491 class FacebookRestClientException extends Exception {
492 }
493
494 // Supporting methods and values------
495
496 /**
497 * Error codes and descriptions for the Facebook API.
498 */
499
500 class FacebookAPIErrorCodes {
501
502 const API_EC_SUCCESS = 0;
503
504 /*
505 * GENERAL ERRORS
506 */
507 const API_EC_UNKNOWN = 1;
508 const API_EC_SERVICE = 2;
509 const API_EC_METHOD = 3;
510 const API_EC_TOO_MANY_CALLS = 4;
511 const API_EC_BAD_IP = 5;
512
513 /*
514 * PARAMETER ERRORS
515 */
516 const API_EC_PARAM = 100;
517 const API_EC_PARAM_API_KEY = 101;
518 const API_EC_PARAM_SESSION_KEY = 102;
519 const API_EC_PARAM_CALL_ID = 103;
520 const API_EC_PARAM_SIGNATURE = 104;
521 const API_EC_PARAM_USER_ID = 110;
522 const API_EC_PARAM_USER_FIELD = 111;
523 const API_EC_PARAM_SOCIAL_FIELD = 112;
524 const API_EC_PARAM_ALBUM_ID = 120;
525
526 /*
527 * USER PERMISSIONS ERRORS
528 */
529 const API_EC_PERMISSION = 200;
530 const API_EC_PERMISSION_USER = 210;
531 const API_EC_PERMISSION_ALBUM = 220;
532 const API_EC_PERMISSION_PHOTO = 221;
533
534 const FQL_EC_PARSER = 601;
535 const FQL_EC_UNKNOWN_FIELD = 602;
536 const FQL_EC_UNKNOWN_TABLE = 603;
537 const FQL_EC_NOT_INDEXABLE = 604;
538
539 public static $api_error_descriptions = array(
540 API_EC_SUCCESS => 'Success',
541 API_EC_UNKNOWN => 'An unknown error occurred',
542 API_EC_SERVICE => 'Service temporarily unavailable',
543 API_EC_METHOD => 'Unknown method',
544 API_EC_TOO_MANY_CALLS => 'Application request limit reached',
545 API_EC_BAD_IP => 'Unauthorized source IP address',
546 API_EC_PARAM => 'Invalid parameter',
547 API_EC_PARAM_API_KEY => 'Invalid API key',
548 API_EC_PARAM_SESSION_KEY => 'Session key invalid or no longer valid',
549 API_EC_PARAM_CALL_ID => 'Call_id must be greater than previous',
550 API_EC_PARAM_SIGNATURE => 'Incorrect signature',
551 API_EC_PARAM_USER_ID => 'Invalid user id',
552 API_EC_PARAM_USER_FIELD => 'Invalid user info field',
553 API_EC_PARAM_SOCIAL_FIELD => 'Invalid user field',
554 API_EC_PARAM_ALBUM_ID => 'Invalid album id',
555 API_EC_PERMISSION => 'Permissions error',
556 API_EC_PERMISSION_USER => 'User not visible',
557 API_EC_PERMISSION_ALBUM => 'Album not visible',
558 API_EC_PERMISSION_PHOTO => 'Photo not visible',
559 FQL_EC_PARSER => 'FQL: Parser Error',
560 FQL_EC_UNKNOWN_FIELD => 'FQL: Unknown Field',
561 FQL_EC_UNKNOWN_TABLE => 'FQL: Unknown Table',
562 FQL_EC_NOT_INDEXABLE => 'FQL: Statement not indexable',
563 FQL_EC_UNKNOWN_FUNCTION => 'FQL: Attempted to call unknown function',
564 FQL_EC_INVALID_PARAM => 'FQL: Invalid parameter passed in',
565 );
566 }
567
568 $profile_field_array = array(
569 "about_me",
570 "activities",
571 "affiliations",
572 "birthday",
573 "books",
574 "current_location",
575 "education_history",
576 "first_name",
577 "hometown_location",
578 "hs_info",
579 "interests",
580 "is_app_user",
581 "last_name",
582 "meeting_for",
583 "meeting_sex",
584 "movies",
585 "music",
586 "name",
587 "notes_count",
588 "pic",
589 "pic_big",
590 "pic_small",
591 "political",
592 "profile_update_time",
593 "quotes",
594 "relationship_status",
595 "religion",
596 "sex",
597 "significant_other_id",
598 "status",
599 "timezone",
600 "tv",
601 "wall_count",
602 "work_history");
603 ?>

Properties

Name Value
svn:keywords Id