ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/repos/facebook/trunk/facebookapi_php5_restlib.php
Revision: 945
Committed: 2007-08-29T17:54:17-07:00 (17 years, 9 months ago) by douglas
File size: 23169 byte(s)
Log Message:
Why was that executable? Fixed the formatting of their license.

File Contents

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