Skip to content
fb_connect.module 8.32 KiB
Newer Older
/**
 * @file
 * Support for Facebook Connect features
 * 
 * Note that Facebook connect will work properly only with themes that are
 * Facebook Connect aware.
 */

function fb_connect_menu($may_cache) {
  $items = array();
  
  if ($may_cache) {
    $items[] = array('path' => 'fb/connect/receiver',
                     'callback' => 'fb_connect_receiver',
                     'type' => MENU_CALLBACK,
                     'access' => TRUE,
		     );
    $items[] = array('path' => 'fb/connect/expire',
		     'callback' => 'fb_connect_expire',
		     '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 = '
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<body>
  <!-- http://wiki.developers.facebook.com/index.php/Cross_Domain_Communication_Channel -->
  <script src="http://static.ak.connect.facebook.com/js/api_lib/v0.4/XdCommReceiver.debug.js" type="text/javascript"></script>
</body>
</html>    
';
  print $output;
  exit();
  die();
}

/**
Dave Cohen's avatar
Dave Cohen committed
 * First attempt to get rid of Facebook's cookies.  Not working
 * as desired, so this is deprecated.  Instead we redirect user on logout.
 */
function fb_connect_expire($apikey) {
  $fb_app = fb_get_app(array('apikey' => $apikey));
  $fb = fb_api_init($fb_app, FB_FBU_CURRENT);
  //$result = $fb->expire_session();

  // http://forum.developers.facebook.com/viewtopic.php?id=21879
  // Use next parameter to return to our logout.
  //drupal_goto("http://www.facebook.com/logout.php?app_key={$fb_app->apikey}&session_key={$session_key}&next=" . url('logout', NULL, NULL, TRUE));
  drupal_goto('logout');
  
}

/**
 * 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) {
  $fb = fb_api_init($fb_app, FB_FBU_CURRENT);
  $fbu = $fb->get_loggedin_user();
  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;
}

function fb_connect_fb($op, $data, &$return) {
  //dpm(func_get_args(), "fb_connect_fb($op)");
}

/**
 * Implementation of hook_user
 *
 * On logout, redirect the user so facebook can expire their session.
Dave Cohen's avatar
Dave Cohen committed
 * 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("fb/connect/expire/{$fb_app->apikey}", 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;
  
  if ($fb_app && !$features[$fb_app->apikey])
    $features[$fb_app->apikey] = array('fb_app' => $fb_app,
				       'features' => array());
    $features[$fb_app->apikey]['features'][$feature] = $feature;
  return $features;
}

/**
 * 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;
  $feature_data = fb_connect_require_feature();
  if (count($feature_data)) {
    foreach ($feature_data as $data) {
      $fb_app = $data['fb_app'];
      $features = $data['features'];
      // drupal_add_js cannot add external javascript, so we use hook_footer instead.
      $output = '<script src="http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php" type="text/javascript"></script>';
      $output .= "\n";
      $feature_list = '["' . implode('","', $features) . '"]';
Dave Cohen's avatar
Dave Cohen committed
      // 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 .= "
<script type=\"text/javascript\">
  $(document).ready(function() {
    FB_RequireFeatures({$feature_list}, function () {

      //FB.FBDebug.logLevel = 4;
      //FB.FBDebug.isEnabled = true;

      FB.Facebook.init(\"{$fb_app->apikey}\", \"{$receiver}\");
Dave Cohen's avatar
Dave Cohen committed
    }
    // Call function which only work after FB.Facebook.init has been called.
    $output .= "
<script type=\"text/javascript\">
  $(document).ready(fb_connect_init);
</script>\n";
  }
  return $output;

}


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));
      $fbu = fb_connect_already_loggedin($fb_app);
      $fb = fb_connect_app_init($fb_app);
      fb_connect_require_feature('XFBML', $fb_app);
      
      $base = drupal_get_path('module', 'fb_connect');
      drupal_add_js(array('fb_connect' => array(
                            'fbu' => $fbu ? $fbu : 0,
                            'logout_url' => url('logout'),
                            'enable_login' => TRUE,
                          ),
                    ), 'setting');
      drupal_add_js($base . '/fb_connect.js');
      
      // TODO: make content and login-button configurable
      if ($fbu) {
        $content = "You're connected, <fb:name uid=$fbu useyou=false></fb:user>.
<fb:profile-pic uid=$fbu></fb:profile_pic>
<fb:login-button onclick='fb_connect_logout_onclick();' autologoutlink=true></fb:login-button>";
      } else {
        $content = "This button should allow you to log in with your facebook credentials.
<fb:login-button onclick='fb_connect_login_onclick();'></fb:login-button>";
      }
      
      $block = array(
        'subject' => t('Login via Facebook'),
        'content' => $content,
      );
      return $block;