'fb/connect/receiver', 'callback' => 'fb_connect_receiver', 'type' => MENU_CALLBACK, 'access' => TRUE, ); } return $items; } /** * Without a receiver file, cross-domain javascript will not work. * * In their infinite wisdom, facebook has decreed that the URL for * this static page be in the same place as the app's callback URL. * So we have to make a Drupal callback for what would otherwise be a * simple file. */ function fb_connect_receiver() { $output = ' '; print $output; exit(); die(); } /** * Prepare for fbConnect use. Because a single Drupal might support * multiple apps, we don't know in advance which is the fbConnect app. * Theoretically, it might be possible to simultaneously use multiple * apps and fbConnect, but my suspicion is facebook would throw a * total hissy-fit if you tried. */ function fb_connect_app_init($fb_app) { if ($fb = fb_api_init($fb_app, FB_FBU_CURRENT)) { $fbu = $fb->get_loggedin_user(); // TODO: sometimes this method indicates we are logged in when we really are not. Find a way to verify. if ($fbu) { // The user has authorized the app and we now know something about them. Use a hook to trigger the actions of other modules. fb_invoke(FB_OP_APP_IS_AUTHORIZED, array('fbu' => $fbu, 'fb_app' => $fb_app, 'fb' => $fb)); } // Store state in session if (!$_SESSION['fb_connect']) { $_SESSION['fb_connect'] = array(); } $_SESSION['fb_connect'][$fb_app->apikey] = $fbu; return $fb; } } /** * Are we already logged in to fbConnect? */ function fb_connect_already_loggedin($fb_app) { if ($_SESSION['fb_connect']) return $_SESSION['fb_connect'][$fb_app->apikey]; return FALSE; } /** * Which apps are fbConnect enabled? */ function fb_connect_enabled_apps() { // We do a bit of work for each enabled app, so really we want to restrict this list to only apps which have been "turned on". // But for now we're lazy and just get the list of all apps. $apps = fb_get_all_apps(); return $apps; } /** * Implementation of hook_fb(). */ function fb_connect_fb($op, $data, &$return) { //dpm(func_get_args(), "fb_connect_fb($op)"); if ($op == FB_OP_CURRENT_APP) { // This will cause fb.module to set the global $fb when user is logged in via fbConnect. if ($apikey = $GLOBALS['fb_connect_apikey']) { // see fb_session.inc $return = fb_get_app(array('apikey' => $apikey)); } } } /** * Implementation of hook_user * * On logout, redirect the user so facebook can expire their session. * Should be a facebook API to do this, but there's none I know of. */ function fb_connect_user($op, &$edit, &$account, $category = NULL) { if ($op == 'logout') { $apps = fb_connect_enabled_apps(); foreach ($apps as $fb_app) { try { $fb = fb_api_init($fb_app, FB_FBU_CURRENT); if ($fb && $fb->api_client->session_key) { // Log out of facebook $session_key = $fb->api_client->session_key; // http://forum.developers.facebook.com/viewtopic.php?id=21879 // Use next parameter to expire session. drupal_goto("http://www.facebook.com/logout.php?app_key={$fb_app->apikey}&session_key={$session_key}&next=" . url('', NULL, NULL, TRUE)); } } catch (Exception $e) { fb_log_exception($e, t('Failed to log out of fbConnect session')); } } } } /** * Allows other modules to specify which Facebook Connect features are * required. This will affect how the FB_RequireFeatures javascript method is * called. */ function fb_connect_require_feature($feature = NULL, $fb_app = NULL) { if ($feature && !isset($fb_app)) $fb_app = $GLOBALS['fb_app']; // some features may apply without an app, but for now let's enforce that an app is required. if ($feature && !$fb_app) return; static $features; if (!$features) $features = array(); if ($fb_app && !$features[$fb_app->apikey]) $features[$fb_app->apikey] = array('fb_app' => $fb_app, 'features' => array()); if ($feature) $features[$fb_app->apikey]['features'][$feature] = $feature; return $features; } /** * Add an option when initializing facebook's javascript api. */ function fb_connect_init_option($option = NULL, $value = NULL, $fb_app = NULL) { if ($option && !isset($fb_app)) $fb_app = $GLOBALS['fb_app']; if ($option && !$fb_app) return; static $options; if (!$options) $options = array(); if ($fb_app && !$options[$fb_app->apikey]) { $options[$fb_app->apikey] = array(); } if ($option) $options[$fb_app->apikey][$option] = $value; return $options; } /** * Include facebook javascript in the footer of the current page. */ function fb_connect_footer($is_front) { // Do nothing on FBML pages if (function_exists('fb_canvas_is_fbml') && fb_canvas_is_fbml()) return; global $base_path; $feature_data = fb_connect_require_feature(); $option_data = fb_connect_init_option(); if (count($feature_data)) { foreach ($feature_data as $data) { // Give other modules a chance to add javascript which executes after init. $extra = fb_invoke(FB_OP_CONNECT_JS_INIT, $data, array()); $extra_js = implode("\n", $extra); $fb_app = $data['fb_app']; $features = $data['features']; $options = json_encode($option_data[$fb_app->apikey]); // drupal_add_js cannot add external javascript, so we use hook_footer instead. $output = ''; $output .= "\n"; $feature_list = '["' . implode('","', $features) . '"]'; // Put together the URL for the receiver. The prefix must be identical to the apps callback URL. $receiver = fb_get_callback_url($fb_app) . "fb/connect/receiver"; $output .= " \n"; } // Call function which only work after FB.Facebook.init has been called. $output .= " \n"; } return $output; } /** * Implementation of hook_block. */ function fb_connect_block($op = 'list', $delta = 0, $edit = array()) { if ($op == 'list') { $items = array(); foreach (fb_connect_enabled_apps() as $fb_app) { $d = 'login_' . $fb_app->label; $items[$d] = array( 'info' => t('Facebook Connect Login to !app', array('!app' => $fb_app->title)), ); } return $items; } else if ($op == 'configure') { // TODO } else if ($op == 'save') { // TODO } else if ($op == 'view') { if (strpos($delta, 'login_') === 0) { // Login block $label = substr($delta, 6); // length of 'login_' $fb_app = fb_get_app(array('label' => $label)); $fb = fb_connect_app_init($fb_app); $fbu = fb_connect_already_loggedin($fb_app); fb_connect_require_feature('XFBML', $fb_app); fb_connect_init_option('reloadIfSessionStateChanged', TRUE, $fb_app); //fb_connect_init_option('doNotUseCachedConnectState', TRUE, $fb_app); $base = drupal_get_path('module', 'fb_connect'); drupal_add_js(array('fb_connect' => array( 'fbu' => $fbu ? $fbu : 0, // XXX 'logout_url' => url('logout'), // XXX 'front_url' => url(''), 'enable_login' => TRUE, ), ), 'setting'); drupal_add_js($base . '/fb_connect.js'); // TODO: make content and login-button configurable if ($fbu) { $content = "You're connected, . "; } else { $content = "This button should allow you to log in with your facebook credentials. "; } $block = array( 'subject' => t('Login via Facebook'), 'content' => $content, ); return $block; } } } ?>