/[drupal]/contributions/modules/fb/fb.module
ViewVC logotype

Contents of /contributions/modules/fb/fb.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.56 - (show annotations) (download) (as text)
Tue Oct 27 21:24:06 2009 UTC (4 weeks, 2 days ago) by yogadex
Branch: MAIN
Changes since 1.55: +7 -7 lines
File MIME type: text/x-php
Changed url alter functions.  http://drupal.org/node/530352#comment-2186004
1 <?php
2 // $Id: fb.module,v 1.55 2009/10/27 20:39:52 yogadex Exp $
3
4 // hook_fb
5 define('FB_HOOK', 'fb');
6
7 // Ops for hook_fb.
8 define('FB_OP_GET_APP', 'get_app'); // Load data from a known app
9 define('FB_OP_GET_ALL_APPS', 'get_all_apps'); // Load data about all apps
10
11 define('FB_OP_CURRENT_APP', 'current_app'); // determine active app in canvas page or facebook connect
12 define('FB_OP_INITIALIZE', 'init'); //
13 define('FB_OP_POST_INIT', 'post init'); //
14
15 define('FB_OP_EXIT', 'exit'); // End an FB callback
16 define('FB_OP_GET_FBU', 'get_fbu'); // Query the local user's FB account
17 define('FB_OP_GET_INFINITE_SESSION', 'get_inf_sess'); // Query infinite session data
18 define('FB_OP_GET_USER_SESSION', 'get_user_sess');
19
20 define('FB_OP_PRE_USER', 'pre_user'); // Before account creation, fb_user.module
21 define('FB_OP_POST_USER', 'post_user'); // After account creation, fb_user.module
22 define('FB_OP_APP_IS_AUTHORIZED', 'app_authorized'); // Invoked if user has authorized an app. Triggers creation of user accounts or authmap entries
23
24 define('FB_OP_SET_PROPERTIES', 'set_props'); // build props for admin.setAppProperties
25 define('FB_OP_LIST_PROPERTIES', 'list_props'); // list of known properties for admin.getAppProperties
26
27 define('FB_OP_CONNECT_JS_INIT', 'fb_connect_js_init'); // A chance to customize fbConnect javascript
28 define('FB_OP_CANVAS_FBJS_INIT', 'fb_canvas_js_init'); // A chance to customize FBJS.
29
30 // node_access realms (belongs here?)
31 define('FB_GRANT_REALM_FRIEND', 'fb_friend');
32 define('FB_GRANT_REALM_GROUP', 'fb_group');
33
34 // When initializing Facebook API, which user to log in as:
35 define('FB_FBU_INFINITE_SESSION', 'fbu_infinite'); // Some APIs still require a session, use no session where possible
36 define('FB_FBU_NO_SESSION', 'fbu_no_session'); // http://wiki.developers.facebook.com/index.php/Category:Sessionless_API
37
38 // NOTE: on Connect Pages, using anything other than FB_FBU_CURRENT will cause cookies to be set which cause problems on subsequent pages. So only use something other than FB_FBU_CURRENT if you absolutely must!
39
40 define('FB_FBU_CURRENT', 'fbu_current'); // Canvas pages and Connect pages
41 define('FB_FBU_ANY', 'fbu_any'); // Use current user on canvas page, fall back to infinite session otherwise.
42
43 //// Constants for internal use
44 define('FB_APP_CURRENT', '000_app_current'); // Canvas pages only. 000 makes it appear first in options list
45
46 /**
47 * Implementation of hook_init
48 *
49 * Determines whether we are servicing a Facebook App request.
50 *
51 * We invoke our hook, first to determine which application is being invoked.
52 * (Because we support more than one in the same Drupal instance.) Then, we
53 * notify interested modules in various events.
54 *
55 */
56 function fb_init() {
57 global $fb, $fb_app; // Set by this function.
58
59 // http://drupal.org/node/329810
60 if (!function_exists('arg')) {
61 // Ensure arg function is defined.
62 drupal_bootstrap(DRUPAL_BOOTSTRAP_PATH);
63 }
64
65 if (arg(0) != 'admin') {
66 // Session sanity check. This is relevant on iframe pages when user once
67 // had the app added, but has since removed it. This is a bit of a hack
68 // because we rely on the fb_... params passed by facebook.
69 if (isset($_SESSION['fb_frame_params']) &&
70 $_REQUEST['fb_sig']) {
71 if ($_REQUEST['fb_sig_session_key'] != $_SESSION['fb_frame_params']['session_key']) {
72 // The session key from facebook has changed. Treat this as a new session.
73 $req = array();
74 foreach ($_REQUEST as $key => $val) {
75 if (strpos($key, 'fb_') === 0)
76 $req[] = $key . '=' . $val;
77 }
78 $url = url($_REQUEST['q'], array('query' => $req, 'absolute' => TRUE));
79 if (fb_verbose())
80 watchdog('fb_debug', 'Facebook session key was %old, now %new. Destroying session and sending user to %url.',
81 array('%old' => $_SESSION['fb_frame_params']['session_key'],
82 '%new' => $_REQUEST['fb_sig_session_key'],
83 '%url' => $url));
84
85 session_destroy();
86 drupal_goto($url);
87 }
88 }
89 }
90
91 // Purge out-of-date session info
92 if (isset($_SESSION['fb_frame_params']) &&
93 $_SESSION['fb_frame_params']['expires'] &&
94 $_SESSION['fb_frame_params']['expires'] < time()) {
95 unset($_SESSION['fb_frame_params']);
96 }
97
98 // Perform sanity check, help users who skip the README.
99 if (!variable_get('fb_settings_check', FALSE) && user_access('access administration pages')) {
100 drupal_set_message(t('!drupal_for_facebook has been enabled, but not properly installed. Please read the !readme.',
101 array('!drupal_for_facebook' => l(t('Drupal for Facebook'), 'http://drupal.org/project/fb'),
102 // This link should work with clean URLs
103 // disabled.
104 '!readme' => '<a href='. base_path() . drupal_get_path('module', 'fb') .'/README.txt>README.txt</a>')), 'error');
105 }
106
107 // Ask other modules for app detail
108 $fb_app = fb_invoke(FB_OP_CURRENT_APP);
109
110 if ($fb_app) {
111 // we are in a callback
112
113 // For canvas pages, use current user, never infinite session.
114 $fb = fb_api_init($fb_app, FB_FBU_CURRENT);
115
116 if ($fb) {
117 // Give other modules a chance to initialize, require login, etc...
118 fb_invoke(FB_OP_INITIALIZE, array('fb_app' => $fb_app,
119 'fb' => $fb));
120
121 // See if the facebook user id is known
122 if ($fbu = $fb->get_loggedin_user()) {
123 fb_invoke(FB_OP_APP_IS_AUTHORIZED, array('fb_app' => $fb_app,
124 'fb' => $fb,
125 'fbu' => $fbu));
126 }
127 }
128 else
129 watchdog('fb', "URL indicates a facebook app, but could not initialize Facebook", array(), WATCHDOG_ERROR);
130
131 }
132
133 fb_invoke(FB_OP_POST_INIT, array('fb_app' => $fb_app,
134 'fb' => $fb));
135 }
136
137
138
139 /**
140 * Include the necessary facebook-platform code and initialize the API object.
141 *
142 * @param fbu To log into facebook as a particular user, pass the facebook id.
143 * This is useful during cron jobs, for example, but rarely if ever needed on
144 * a canvas page. If no valid session key is known for the user, this call
145 * will still return a facebook reference.
146 *
147 * If FB_FBU_INFINITE_SESSION is passed, we attempt to log into an infinite
148 * session we've configured.
149 *
150 * If FB_FBU_ANY is passed in, we will log in as the canvas page user if
151 * already logged in. Otherwise we try the infinite session, if configured.
152 *
153 * Future calls into the the facebook api could fail for various reasons. For
154 * one, we may fail to log in as the specified user. This call does not
155 * actually contact facebook to test the connection, it just sets things up so
156 * that when the connection is needed, it might work. Even if the connection
157 * is established, the user may not have sufficient permission to whatever you
158 * are asking facebook to do.
159 *
160 */
161 function fb_api_init($fb_app, $fbu = FB_FBU_CURRENT) {
162 //dpm(func_get_args(), "fb_api_init");
163 //$trace = debug_backtrace();
164 //dpm($trace, "fb_api_init call stack");
165
166 static $cache = array();
167
168 // This helps with uncaught exceptions. However, it should be configurable
169 // or at least not overwrite previously declared handler.
170 set_exception_handler('fb_handle_exception');
171
172 if (!count($cache)) {
173 $filename = variable_get('fb_api_file', 'facebook-platform/php/facebook.php');
174 if (!include($filename)) {
175 $message = t('Failed to find the Facebook client libraries at %filename. Read the !readme and follow the instructions carefully.',
176 array('!drupal_for_facebook' => l(t('Drupal for Facebook'), 'http://drupal.org/project/fb'),
177 // This link should work with clean URLs disabled.
178 '!readme' => '<a href='.base_path() . '/' . drupal_get_path('module', 'fb') . '/README.txt>README.txt</a>',
179 '%filename' => $filename,
180 ));
181 drupal_set_message($message, 'error');
182 watchdog('fb', $message);
183 return NULL;
184 }
185 }
186
187 global $facebook_config;
188 $facebook_config['debug'] = variable_get('fb_debug', FALSE); // set TRUE for debug output from FB API
189
190 if (!$cache[$fb_app->apikey]) {
191 $cache[$fb_app->apikey] = array();
192 }
193 $fbu_orig = $fbu;
194
195 // Determine the actual facebook user id to use.
196 if ($GLOBALS['fb'] && $GLOBALS['fb']->api_key == $fb_app->apikey &&
197 ($fbu == FB_FBU_CURRENT || $fbu == FB_FBU_ANY ||
198 $fbu == $GLOBALS['fb']->get_loggedin_user())) {
199 return $GLOBALS['fb'];
200 }
201 else if ($GLOBALS['fb']->api_key == $fb_app->apikey &&
202 ($fbu == FB_FBU_CURRENT || $fbu == FB_FBU_ANY)
203 && isset($_SESSION['fb_frame_params']) && !$_REQUEST['fb_sig']) {
204 $params = $_SESSION['fb_frame_params'];
205 $fbu = $params['user'];
206 $session = $params['session_key'];
207 }
208 else if ($GLOBALS['fb'] && $GLOBALS['fb']->api_key == $fb_app->apikey &&
209 $fbu == FB_FBU_CURRENT) {
210 // No current user to use, probably anonymous canvas page.
211 return $GLOBALS['fb'];
212 }
213 else if ($fbu == FB_FBU_INFINITE_SESSION || $fbu == FB_FBU_ANY) {
214 // Learn the infinite session id and key
215 $data = fb_invoke(FB_OP_GET_INFINITE_SESSION, array('fb_app' => $fb_app,
216 'fb' => $GLOBALS['fb']),
217 array());
218 $fbu = $data[0];
219 $session = $data[1];
220 }
221 else if ($fbu != FB_FBU_NO_SESSION) {
222 // FB user id passed in. If we happen to have valid session info for
223 // them, we can log in as them.
224 $data = fb_invoke(FB_OP_GET_USER_SESSION,
225 array('fb_app' => $fb_app,
226 'fb' => $fb,
227 'fbu' => $fbu),
228 array());
229
230 if (count($data) && $data[0] && $data[1]) {
231 $fbu = $data[0];
232 $session = $data[1];
233 }
234 }
235
236 if (!$cache[$fb_app->apikey][$fbu]) {
237 // We don't have a cached resource for this app/user combo, so we're going to create one.
238 $fb = new Facebook($fb_app->apikey, $fb_app->secret);
239
240 // Iframes may link or redirect within the iframe, in which case facebook
241 // will not provide all its normal variables. To prepare for such a case,
242 // we cache the facebook parameters in the session.
243 // We update the cache whenever possible, to keep it current.
244 if ($fb->in_frame() && $fb->fb_params) {
245 $_SESSION['fb_frame_params'] = $fb->fb_params; // hacky to use fb's internal data structure
246 }
247
248 // If we learned the session, above, use it
249 if ($fbu && $session) {
250 $fb->set_user($fbu, $session);
251 }
252 else if ($fbu && $fbu == $fb->get_loggedin_user()) {
253 // Canvas page or Connect page, current user is logged in already.
254 // Nothing to do here.
255 }
256 else if ($fbu == FB_FBU_NO_SESSION) {
257 $fb->set_user(NULL, NULL);
258 }
259
260 // Cache the result, in case we're called again.
261 $cache[$fb_app->apikey][$fbu] = $fb;
262
263 // Note that facebook api has not actually logged into facebook yet.
264 // We won't really know if our session is valid until later.
265 // get_loggedin_user does not really test it.
266 if ($fbu_orig != FB_FBU_NO_SESSION &&
267 $fbu_orig != FB_FBU_CURRENT && !$fb->get_loggedin_user()) {
268 // An FBU other than CURRENT was specified, but we failed to log in.
269 watchdog('fb', 'Failed to log into facebook app %app as user %user',
270 array('%app' => $fb_app->title,
271 '%user' => $fbu_orig), WATCHDOG_ERROR);
272 }
273 }
274
275 $fb = $cache[$fb_app->apikey][$fbu];
276 return $fb;
277 }
278
279 /**
280 * Wrapper function for fb_api_init. This helps for functions that should
281 * work whether or not we are on a canvas page. For canvas pages, the active
282 * fb object is used. For non-canvas pages, it will initialize the API using
283 * an infinite session, if configured.
284 *
285 * @param $fb_app Note this is ignored on canvas pages.
286 *
287 * This is for internal use. Third party modules use fb_api_init().
288 */
289 function _fb_api_init($fb_app = NULL) {
290 $fb = $GLOBALS['fb']; // Default to active app on canvas pages
291 if (!$fb && $fb_app)
292 // Otherwise, log into facebook api.
293 $fb = fb_api_init($fb_app, FB_FBU_ANY);
294
295 if (!$fb) {
296 watchdog('fb', '%function unable to initialize Facebook API.',
297 array('%function' => '_fb_api_init()'), WATCHDOG_ERROR);
298 return;
299 }
300 else
301 return $fb;
302 }
303
304 /**
305 * Sometimes calls to fb_api_init succeed, but calls to the client api
306 * will fail because cookies are obsolete or what have you. This
307 * function makes a call to facebook to test the session. Expensive,
308 * so use only when necessary.
309 */
310 function fb_api_check_session($fb) {
311 // TODO: caching
312 $success = FALSE;
313 try {
314 $is_user = $fb->api_client->users_isAppUser();
315 // Does not matter what is returned, as long as exception is not thrown.
316 $success = TRUE;
317 }
318 catch (Exception $e) {
319 $success = FALSE;
320 }
321 return $success;
322 }
323
324 /**
325 * Returns the facebook user id currently visiting a canvas page, or if set_user has been called.
326 * Unlike fb_get_fbu(), works only on canvas pages or when infinite session has been initialized.
327 */
328 function fb_facebook_user($fb = NULL) {
329 if (!isset($fb))
330 $fb = $GLOBALS['fb'];
331
332 if (!$fb)
333 return;
334
335 $fbu = $fb->get_loggedin_user();
336 if ($fb->api_client->error_code) {
337 if (fb_verbose()) {
338 watchdog('fb', 'Failed to get Facebook user id. detail: !detail',
339 array('!detail' => print_r($_REQUEST, 1)), WATCHDOG_ERROR);
340 }
341 }
342 return $fbu;
343 }
344
345 /**
346 * Facebook provides a method, users_isAppUser(), which is buggy and
347 * unreliable. So we need to implement our own.
348 */
349 function fb_is_app_user($fb) {
350 if ($fb->api_client->added || $fb->api_client->is_user)
351 return TRUE;
352 else
353 return $fb->api_client->users_isAppUser;
354 }
355
356
357 /**
358 * Given a local user id, find the facebook id.
359 */
360 function fb_get_fbu($uid, $fb_app = NULL) {
361 // default to current app (only set if we're in a FB callback)
362 if (!$fb_app)
363 $fb_app = $GLOBALS['fb_app'];
364
365 // Accept either a user object or uid passed in.
366 if (is_object($uid) && $uid->fbu)
367 return $uid->fbu;
368 else if (is_object($uid))
369 $uid = $uid->uid;
370
371 // User management is handled by another module. Use our hook to ask for mapping.
372 $fbu = fb_invoke(FB_OP_GET_FBU, array('fb_app' => $fb_app,
373 'uid' => $uid,
374 'fb' => $GLOBALS['fb']));
375
376 return $fbu;
377 }
378
379 /**
380 * Convenience method to get an apps callback URL.
381 *
382 * TODO: This code will probably not handle every case and may need some work.
383 */
384 function fb_get_callback_url($fb_app) {
385 $url = url('', array('absolute' => TRUE)) . FB_SETTINGS_APP_NID . '/'. $fb_app->nid . '/';
386 return $url;
387 }
388
389 /**
390 * Convenience method to get app info based on apikey or nid.
391 */
392 function fb_get_app($search_data) {
393 // $search_data can be an apikey, or an array of other search params.
394 if (!is_array($search_data))
395 $search_data = array('apikey' => $search_data);
396
397 $fb_app = fb_invoke(FB_OP_GET_APP, $search_data);
398 return $fb_app;
399 }
400
401 /**
402 * Convenience method to return a list of all known apps, suitable for form
403 * elements.
404 */
405 function fb_get_app_options($include_current = FALSE) {
406 $apps = fb_get_all_apps();
407 $options = array();
408 if ($include_current)
409 $options[FB_APP_CURRENT] = t('<current>');
410 foreach ($apps as $app) {
411 $options[$app->nid] = $app->title;
412 }
413 return $options;
414 }
415
416 /**
417 * Convenience method to return array of all know fb_apps.
418 */
419 function fb_get_all_apps() {
420 $apps = fb_invoke(FB_OP_GET_ALL_APPS, NULL, array());
421 return $apps;
422 }
423
424 /**
425 * A convenience method for returning a list of facebook friends.
426 *
427 * This should work efficiently in canvas pages for finding friends of
428 * the current user. In other cases it tries to work, but will be an
429 * expensive operation and only succeed when the user is logged in via
430 * Connect, or has created an infinite session.
431 *
432 * @return: an array of facebook ids
433 */
434 function fb_get_friends($fbu, $fb_app = NULL) {
435 static $cache = array();
436 if (!$fb_app)
437 $fb_app = $GLOBALS['fb_app'];
438
439 // Facebook only allows us to query the current user's friends, so let's try
440 // to log in as that user. It will only actually work if they are the
441 // current user of a canvas page, or they've signed up for an infinite
442 // session.
443 $fb = fb_api_init($fb_app, $fbu);
444 if (!$fb || !$fbu)
445 return;
446
447 if (!isset($cache[$fbu])) {
448 if ($fb === $GLOBALS['fb'] &&
449 $fbu == fb_facebook_user($fb))
450 $items = $fb->api_client->friends_get();
451 // friends_get does not work in cron call, so we double check.
452 if (!$items || !count($items)) {
453 $logged_in = fb_facebook_user($fb);
454 $query = "SELECT uid2 FROM friend WHERE uid1=$fbu";
455 $result = $fb->api_client->fql_query($query);
456 fb_report_errors($fb);
457
458 $items = array();
459 if (is_array($result))
460 foreach ($result as $data) {
461 $items[] = $data['uid2'];
462 }
463 }
464 // Facebook's API has the annoying habit of returning an item even if user
465 // has no friends. We need to clean that up.
466 if (!$items[0])
467 unset($items[0]);
468
469 $cache[$fbu] = $items;
470 }
471
472 return $cache[$fbu];
473 }
474
475 // Return array of facebook gids
476 function fb_get_groups($fbu, $fb_app = NULL) {
477 $items = array();
478 $groups = fb_get_groups_data($fbu);
479
480 if ($groups && count($groups))
481 foreach ($groups as $data) {
482 $items[] = $data['gid'];
483 }
484 return $items;
485 }
486
487 function fb_get_groups_data($fbu, $fb_app = NULL) {
488 static $cache = array();
489
490 $fb = _fb_api_init($fb_app);
491 if (!$fb || !$fbu)
492 return;
493
494 if (!isset($cache[$fbu])) {
495 $cache[$fbu] = $fb->api_client->groups_get($fbu, NULL);
496 }
497
498 return $cache[$fbu];
499 }
500
501
502 // deprecated since creation of fb_user module, but cron hook still uses this.
503 function fb_user_load($fbu = NULL) {
504 global $user;
505 if (!$fbu)
506 // default to current logged in user
507 $fbu = fb_facebook_user();
508 if ($fbu && $user->fbu == $fbu) {
509 return $user;
510 }
511 if ($fbu) {
512 $account = user_external_load("$fbu-$fb_app->apikey@facebook.com");
513 if (!$account)
514 $account = user_external_load("$fbu@facebook.com");
515 if (!$account)
516 $account = user_load(array('uid' => variable_get('fb_facebook_user', 2)));
517 if (!$account)
518 watchdog('fb', 'Failed to load user from facebook fbu=%fbu',
519 array('%fbu' => $fbu), WATCHDOG_ERROR);
520 $account->fbu = $fbu;
521 return $account;
522 }
523 }
524
525
526 function fb_form_alter(&$form, &$form_state, $form_id) {
527 // Because facebook users don't have email, it can't be required on user form
528 if ($form_id == 'user_register') {
529 if (user_access('administer users')) {
530 $form['mail']['#required'] = FALSE;
531 }
532 }
533 if ($form_id == 'user_edit') {
534 if (user_access('administer users')) {
535 $form['account']['mail']['#required'] = FALSE;
536 }
537 }
538 }
539
540
541 function fb_menu() {
542 $items = array();
543
544 // When forms are submitted directly to us, we cache the results,
545 // and show them later via this callback
546 $items['fb/form_cache'] = array(
547 'page callback' => '_fb_form_cache_cb',
548 'type' => MENU_CALLBACK,
549 'access callback' => TRUE);
550
551 return $items;
552 }
553
554 /**
555 * When exiting we need to do some special stuff for forms
556 */
557 function fb_exit($destination = NULL) {
558 global $fb_app, $fb;
559 if ($fb_app && $fb) {
560 fb_invoke(FB_OP_EXIT, array('fb_app' => $fb_app,
561 'fb' => $GLOBALS['fb']),
562 $destination);
563 }
564 }
565
566 function _fb_form_cache_cb($cid) {
567 // Facebook started appending a '?', we need to get rid of it.
568 if ($pos = strpos($cid, '?'))
569 $cid = substr($cid, 0, $pos);
570
571 watchdog('fb', "Returning cached form page $cid");
572 $cache = cache_get($cid, 'cache_page');
573 // Don't clear, as user may refresh browser. Cache will expire eventually.
574 // cache_clear_all($cid, 'cache_page');
575 print $cache->data;
576 exit();
577 }
578
579 function fb_session_key_form() {
580 global $fb_app;
581 $form = array('auth_token' => array('#type' => 'textfield',
582 '#title' => t('One-time code'),
583 '#description' => t('If you do not have a one-time code, you can get one !here.',
584 array('!here' => l(t('here'), 'http://www.facebook.com/code_gen.php?v=1.0&api_key='.$fb_app->apikey))),
585 ),
586 'submit' => array('#type' => 'submit',
587 '#value' => t('Submit')),
588
589 '#redirect' => FALSE, /* necessary when submitting via facebook */
590 );
591 return $form;
592 }
593
594 /**
595 * Invoke hook_fb.
596 */
597 function fb_invoke($op, $data = NULL, $return = NULL) {
598 foreach (module_implements(FB_HOOK) as $name) {
599 $function = $name . '_' . FB_HOOK;
600 try {
601 $function($op, $data, $return);
602 }
603 catch (Exception $e) {
604 fb_log_exception($e, t('Exception calling %function(%op)',
605 array('%function' => $function,
606 '%op' => $op)));
607 }
608 }
609 return $return;
610 }
611
612 /**
613 * This method will clean up URLs. When serving canvas pages, extra
614 * information is included in URLs (see fb_settings.inc). This will remove
615 * the extra information.
616 */
617 function fb_scrub_urls($content) {
618 foreach (array(FB_SETTINGS_APP_NID, FB_SETTINGS_PAGE_TYPE) as $key) {
619 $patterns[] = "|$key/[^/]*/|";
620 $replacements[] = "";
621 }
622 $content = preg_replace($patterns, $replacements, $content);
623 return $content;
624 }
625
626 /**
627 * Implementation of hook_node_grants.
628 *
629 * We put this here so all facebook modules have a standard way to implement
630 * hook_node_access_records. They use that hook to insert records into the
631 * node access table. We use this hook to allow access when the grants are
632 * there.
633 *
634 * DEPRECATED. Not sure where, if anywhere, this belongs.
635 */
636 function fb_node_grantsXXX($account, $op) {
637 $grants = array();
638 $fbu = fb_get_fbu($account);
639 if ($fbu) { // If not anonymous (facebook user not logged in to this app)
640 $friends = fb_get_friends($fbu);
641 // For access purposes, consider a users to be a friend of themself
642 $friends[] = $fbu;
643 if (count($friends))
644 $grants[FB_GRANT_REALM_FRIEND] = $friends;
645
646 $groups = fb_get_groups($fbu);
647 if (count($groups))
648 $grants[FB_GRANT_REALM_GROUP] = $groups;
649 }
650
651 return $grants;
652 }
653
654 /**
655 * Convenience method for displaying facebook api errors.
656 */
657 function fb_report_errors($fb = FB_APP_CURRENT, $message = NULL) {
658 if ($fb == FB_APP_CURRENT) {
659 $fb = $GLOBALS['fb'];
660 }
661 if ($fb) {
662 if ($fb->api_client->error_code) {
663 $message = t('!message Facebook API error %code (see !link).',
664 array('%code' => $fb->api_client->error_code,
665 '!link' => l(t('error codes'), "http://wiki.developers.facebook.com/index.php/Error_codes"),
666 '!message' => $message,
667 ));
668 watchdog('fb', $message, array(), WATCHDOG_ERROR);
669 drupal_set_message($message, 'error');
670 }
671 }
672 }
673
674 function fb_log_exception($e, $text = '', $fb = NULL) {
675 if ($text)
676 $message = $text .': '. $e->getMessage();
677 else
678 $message = $e->getMessage();
679 $message .= ' ' . $e->getCode();
680
681 if ($fb) {
682 $message .= '. (' . t('logged into facebook as %fbu', array('%fbu' => $fb->get_loggedin_user())) . ')';
683 }
684 if (fb_verbose()) {
685 $message .= '<pre>' . $e . '</pre>';
686 }
687 watchdog('fb', $message, array(), WATCHDOG_ERROR);
688 if (user_access('administer fb apps')) {
689 drupal_set_message($message, 'error');
690 }
691 }
692
693 /**
694 * Exception handler for PHP5 exceptions.
695 */
696 function fb_handle_exception($exception) {
697 $message = t('Facebook API exception %message. !trace',
698 array('%message' => $exception->getMessage(),
699 '!trace' => '<pre>'.$exception->getTraceAsString().'</pre>',
700 ));
701 watchdog('fb', $message, array(), WATCHDOG_ERROR);
702 //drupal_set_message($message, 'error');
703 print $message;
704
705 print "<pre>\$_REQUEST:\n";
706 print_r($_REQUEST);
707 print "\n\nREQUEST_URI:\n" . $_SERVER['REQUEST_URI'];
708 print "</pre>";
709
710 }
711
712 /**
713 * Helper function for facebook's users_getInfo API.
714 *
715 * This function makes calls to users_getInfo more efficient, by caching
716 * results in the session, so calls do not always require hitting Facebook's
717 * servers.
718 *
719 * @param $oids
720 * Array of facebook object IDs. In this case they should each be a user id.
721 */
722 function fb_users_getInfo($oids, $fb = NULL, $refresh_cache = FALSE) {
723 if (!$fb) {
724 $fb = $GLOBALS['fb'];
725 }
726 $infos = array();
727
728 if (!is_array($oids))
729 $oids = array();
730
731 if ($fb) {
732 // First try cache
733 if (!$refresh_cache)
734 foreach ($oids as $oid) {
735 if ($info = $_SESSION['fb'][$fb->api_key]['userinfo'][$oid])
736 $infos[] = $info;
737 }
738 if (count($infos) != count($oids)) {
739 // Session cache did not include all users, update the cache.
740 $infos = $fb->api_client->users_getInfo($oids,
741 array('about_me',
742 'affiliations',
743 'name',
744 'is_app_user',
745 'pic',
746 'pic_big',
747 'pic_square',
748 'profile_update_time',
749 'proxied_email',
750 'status',
751 'email_hashes',
752 ));
753 // Update cache with recent results.
754 if (is_array($infos)) {
755 foreach($infos as $info) {
756 $_SESSION['fb'][$fb->api_key]['userinfo'][$info['uid']] = $info;
757 }
758 }
759 }
760
761 return $infos;
762 }
763 }
764
765 /**
766 * Helper function for FBJS files.
767 *
768 * Useful for adding Facebook Javascript, which will be incorporated into
769 * canvas pages or profile boxes. When included this way, javascript must be
770 * embedded inline, rather than refer to an external URL. So this function
771 * will actually read a local file and include the contents inline.
772 */
773 function fb_add_js($filename, $type) {
774 static $cache;
775 if (!$cache) {
776 $cache = array();
777
778 // Add the most basic file we need.
779 $base_file = drupal_get_path('module', 'fb') . '/fb_fbml.js';
780 $base_file .= "?v=".filemtime($base_file);
781 drupal_add_js($base_file, 'module', 'fbml');
782
783 // Add some settings that FBJS code will often need.
784 $baseUrl = url('', array('absolute' => TRUE));
785 drupal_add_js(array('fbjs' => array('baseUrlFb' => $baseUrl,
786 'baseUrl' => fb_scrub_urls($baseUrl),
787 ),
788 ),
789 'setting', 'fbml');
790
791 }
792
793 if (!$cache[$filename]) {
794 if (file_exists($filename)) {
795 // Refresh facebook's cache when file changes
796 $filename .= "?v=".filemtime($filename);
797 }
798 // 'post_settings' is a hack to make our code come after settings. This is
799 // ugly, but we're doing it because there is no "onready" in FBJS.
800 drupal_add_js($filename, 'post_settings', 'fbml');
801 $cache[$filename] = TRUE;
802 }
803 }
804
805 /**
806 * For debugging, add $conf['fb_verbose'] = TRUE; to settings.php.
807 */
808 function fb_verbose() {
809 return variable_get('fb_verbose', NULL);
810 }
811
812 /**
813 * Define custom_url_rewrite_inbound() if not defined already.
814 */
815 if (!function_exists('custom_url_rewrite_inbound')) {
816 function custom_url_rewrite_inbound(&$result, $path, $path_language) {
817 fb_url_inbound_alter($result, $path, $path_language);
818 }
819 }
820
821 /**
822 * Define custom_url_rewrite_outbound() if the url_alter.module is not enabled.
823 */
824 if (!function_exists('custom_url_rewrite_outbound')) {
825 function custom_url_rewrite_outbound(&$path, &$options, $original_path) {
826 fb_url_outbound_alter($path, $options, $original_path);
827 }
828 }
829
830 /**
831 * Implementation of hook_url_outbound_alter().
832 */
833 function fb_url_outbound_alter(&$path, &$options, $original_path) {
834 //dpm(func_get_args(), 'fb_settings_url_rewrite_outbound');
835 $pre = '';
836
837 // Prefix each known value to the URL
838 foreach (array_reverse(_fb_settings_url_rewrite_prefixes()) as $prefix) {
839 if ($value = fb_settings($prefix))
840 $pre .= $prefix . '/'. $value . '/';
841 }
842 $path = $pre . $path;
843
844 return $path;
845 }
846
847 /**
848 * Implementation of hook_url_inbound_alter().
849 *
850 * Rewrite URLs for facebook canvas pages, and connect callbacks.
851 *
852 */
853 function fb_url_inbound_alter(&$result, $path, $path_language){
854 //$origpath = $path;
855 //watchdog('fb_settings', "fb_settings_url_rewrite_inbound($result, $path, $path_language)", array(), WATCHDOG_DEBUG);
856
857 // See if this is a request for us.
858 if (strpos($path, FB_SETTINGS_APP_NID . '/') === 0) {
859 // Too soon for arg() function.
860 $args = explode('/', $path);
861 while (count($args) && in_array($args[0], _fb_settings_url_rewrite_prefixes())) {
862 $key = array_shift($args);
863 $value = array_shift($args);
864 $app_nid = fb_settings($key, $value); // Store for use later.
865 }
866 if ($app_nid = fb_settings(FB_SETTINGS_APP_NID)) {
867 if (count($args)) {
868 $path = implode('/', $args); // remaining args
869 $alias = drupal_lookup_path('source', $path, $path_language); //can't use drupal_get_normal_path, it calls custom_url_rewrite_inbound
870 if ($alias)
871 $path = $alias;
872 }
873 else {
874 // frontpage
875 $path = variable_get('site_frontpage', 'node');
876 $alias = drupal_lookup_path('source', $path, $path_language);
877 if ($alias)
878 $path = $alias;
879 $_REQUEST['destination'] = $path; //required workaround for compatibility with Global Redirect module, best practice?
880 }
881 }
882 }
883 else { //resolve aliases for non-fb-callbacks
884 $alias = drupal_lookup_path('source', $path, $path_language);
885 if ($alias)
886 $path = $alias;
887 }
888
889 $result = $path;
890 }
891
892 /**
893 * This function will be replaced, hopefully, by format_username in D7.
894 *
895 * See http://drupal.org/node/192056
896 */
897 function fb_format_username($account) {
898 $name = !empty($account->name) ? $account->name : variable_get('anonymous', t('Anonymous'));
899 drupal_alter('username', $name, $account);
900 return $name;
901 }
902
903 /**
904 * hook_username_alter().
905 *
906 * Return a user's facebook name, instead of local username.
907 */
908 function fb_username_alter(&$name, $account) {
909 //dpm(func_get_args(), "fb_username_alter($name)");
910 if ($account->fbu && ($name == $account->fbu . '@facebook')) {
911 $info = fb_users_getInfo(array($account->fbu));
912 if ($info[0]['name']) {
913 $name = $info[0]['name'];
914 }
915 }
916 }
917
918 ?>

  ViewVC Help
Powered by ViewVC 1.1.2