FB_USER_OPTION_CREATE_LOGIN,
'map_account' => FB_USER_OPTION_MAP_ALWAYS,
);
return $fb_user_data;
}
/**
* There are several pages where we don't want to automatically create a new
* account or use an account configured for this app.
*/
function _fb_user_special_page() {
// TODO: hopefully this can be simplified.
return ((arg(0) == 'user' && arg(1) == 'login') ||
(arg(0) == 'user' && arg(1) == 'register') ||
arg(0) == 'fb_user' ||
(arg(0) == 'fb' && arg(1) == 'form_cache') ||
(arg(0) == 'fb_app' && arg(1) == 'event') ||
(arg(0) == 'fb_connect' && arg(1) == 'receiver'));
}
/**
* Keep track of when the user has visited the app, and whether they've
* authorized the app or not.
*/
function _fb_user_track($fb, $fb_app, $account) {
// Keep track of all our app users. We need this info when updating
// profiles during cron. We keep session keys in case user has an
// infinite session, and we can actually log in as them during cron.
// In special cases, do not modify the uid column.
$fb_user_data = _fb_user_get_config($fb_app);
if (!$account->uid || $account->uid == $fb_user_data['not_logged_in_uid'] || $account->uid == $fb_user_data['logged_in_uid']) {
// Keep data for fbu, even if we do not know uid.
$uid = 0;
}
else {
// Uid is accurate.
$uid = $account->uid;
}
$result = db_query("UPDATE {fb_user_app} SET time_access=%d, session_key='%s', session_key_expires=%d, uid=%d WHERE apikey='%s' AND fbu=%d",
time(), $fb->api_client->session_key, $fb->session_expires,
$uid,
$fb_app->apikey, fb_facebook_user($fb));
if ($result && !db_affected_rows()) {
// The row for this user was never inserted, or deleted. Insert now.
$fbu = fb_facebook_user($fb);
if ($fbu) {
$info = fb_users_getInfo(array($fbu), $fb);
$data = $info[0];
$result = db_query("INSERT INTO {fb_user_app} (apikey, fbu, added, session_key, session_key_expires, time_access, uid, proxied_email, time_cron) VALUES ('%s', %d, %d, '%s', %d, %d, %d, '%s', %d)",
$fb_app->apikey, $fbu,
$data['is_app_user'],
$fb->session_key, $fb->session_key_expires,
time(),
$uid,
$data['proxied_email'],
0 // time_cron
);
}
}
if ($result === FALSE) {
watchdog('fb_user', "Failed to update fb_user_app table.", array(), WATCHDOG_ERROR);
}
}
/**
* Implementation of hook_fb.
*/
function fb_user_fb($op, $data, &$return) {
$fb_app = isset($data['fb_app']) ? $data['fb_app'] : NULL;
$fb = isset($data['fb']) ? $data['fb'] : NULL;
global $user;
if ($fb_app) {
$fb_user_data = _fb_user_get_config($fb_app);
}
if ($op == FB_OP_POST_INIT) {
// Observe special rules for canvas page users without local accounts
if (!$user->uid && !_fb_user_special_page() && !isset($_REQUEST['form_id'])) {
if ($fbu = fb_facebook_user($fb) && fb_api_check_session($fb) && !$fb->api_client->users_isAppUser()) {
$uid = $fb_user_data['logged_in_uid'];
}
else if (isset($fb_user_data['fb_user'])) {
$uid = $fb_user_data['fb_user']['not_logged_in_uid'];
}
if (isset($uid)) {
// Be careful on maintenance pages.
if (!variable_get('site_offline', FALSE) || user_access('administer site configuration', $account)) {
$account = user_load(array('uid' => $uid));
$valid_user = user_external_login($account);
if (!$valid_user) {
drupal_access_denied();
exit();
}
if (fb_verbose() === 'extreme')
watchdog("fb_user", "fb_user_fb changing user to $uid"); // debug
}
}
}
}
else if ($op == FB_OP_APP_IS_AUTHORIZED) {
// This hook is called on every page request, if the user has authorized the app.
$fbu = $data['fbu']; // The user id on facebook.
// Remember the original uid, in case we have to change it.
$original_uid = $user->uid;
// Make sure session is valid and authmap table is correct.
// Relatively expensive operations, so we perform them only once per session.
if (!isset($_SESSION['fb_user_fbu']) || $_SESSION['fb_user_fbu'] != $fbu) {
if ($valid_session = fb_api_check_session($fb)) {
$_SESSION['fb_user_fbu'] = $fbu;
if ($user->uid != 0 &&
$user->uid != $fb_user_data['logged_in_uid']) {
// Ensure local user has proper authmap entry.
_fb_user_set_authmap($fb_app, $fbu, $user);
}
else {
// We're anonymous. Check authmap to see if there is a local user for this fbu.
// Try the application-specific account.
$account = user_external_load("$fbu-$fb_app->apikey@facebook.com");
if (!$account) {
// Try the cross-application account.
$account = user_external_load("$fbu@facebook.com");
}
if ($account) {
// Honoring facebook accounts in off-line mode causes problems.
if (!variable_get('site_offline', FALSE) ||
user_access('administer site configuration', $account)) {
if (fb_verbose() === 'extreme')
watchdog("fb_user", "fb_user_fb changing user to $account->uid");
$valid_user = user_external_login($account);
if (!$valid_user) {
drupal_access_denied();
exit();
}
}
}
}
}
}
// If we've confirmed the session, user is a facebook user.
if ($user->uid != 0 && $user->uid != $fb_user_data['logged_in_uid'] &&
isset($_SESSION['fb_user_fbu']) && $_SESSION['fb_user_fbu'] == $fbu) {
$user->fbu = $fbu;
}
// Check if the local account needs to be made.
if (!variable_get('site_offline', FALSE) &&
$user->fbu != $fbu &&
(!_fb_user_special_page()) &&
isset($_SESSION['fb_user_fbu'])) {
if (($fb_user_data['create_account'] == FB_USER_OPTION_CREATE_ADD &&
$fb->api_client->users_isAppUser()) ||
($fb_user_data['create_account'] == FB_USER_OPTION_CREATE_LOGIN)) {
// We need to make a local account for this facebook user.
// First choose a name.
if ($fb_user_data['unique_account']) {
$username = "$fbu-$fb_app->label@facebook";
}
else {
$username = "$fbu@facebook";
}
if ($fb_user_data['new_user_rid']) {
$roles = array($fb_user_data['new_user_rid'] => TRUE);
}
else {
$roles = array();
}
$user = fb_user_create_local_user($fb, $fb_app, fb_facebook_user($fb),
array('name' => $username,
'roles' => $roles,
));
$user->fbu = $fbu;
watchdog('fb_user',
t("Created new user !username for application %app",
array('!username' => l($user->name, 'user/' . $user->uid),
'%app' => $fb_app->label)));
}
}
// It's possible the user was already created by another app.
// In this case we need to add our role.
if ($user->fbu == $fbu &&
$fb_user_data['new_user_rid'] &&
!$user->roles[$fb_user_data['new_user_rid']]) {
// there should be an API for this...
db_query('INSERT INTO {users_roles} (uid, rid) VALUES (%d, %d)',
$user->uid, $fb_user_data['new_user_rid']);
watchdog('fb_user', "Added role %role to existing user !username for application %app",
array('!username' => theme('username', $user),
'%app' => $fb_app->label,
'%role' => $fb_user_data['new_user_rid']));
}
// Keep a record of user visiting this app.
_fb_user_track($fb, $fb_app, $user);
}
else if ($op == FB_OP_GET_FBU) {
// This is a request to learn the user's FB id.
$return = _fb_user_get_fbu($data['uid'], $fb_app);
}
else if ($op == FB_OP_GET_USER_SESSION) {
// The fb module is asking for session login information. For example, to
// log in as the user when not on a canvas page. This module may be able
// to provide it, depending on whether the user has logged in, and whether
// the session has expired.
$fbu = $data['fbu'];
$result = db_query("SELECT * FROM {fb_user_app} WHERE apikey = '%s' and fbu = %d AND session_key_expires > %d", $fb_app->apikey, $fbu, time());
$data = db_fetch_object($result);
if ($data && $data->session_key)
// Return array with FB id and apikey.
$return = array($data->fbu, $data->session_key);
}
else if ($op == FB_APP_OP_EVENT) {
// Facebook has notified us of some event.
// We handle some of the events here.
$event_type = $data['event_type'];
// Ensure fb_user_app table accurately reflects whether user has authorized.
if ($event_type == FB_APP_EVENT_POST_AUTHORIZE) {
// User has authorized us to know some details about her.
$fbu = fb_facebook_user($fb);
$proxied_email = fb_user_get_proxied_email($fbu, $fb_app);
// In special cases, do not store the uid column.
$fb_user_data = _fb_user_get_config($fb_app);
// If user has authorized then later removed, there will be a row we can replace
db_query("DELETE FROM {fb_user_app} WHERE apikey = '%s' AND fbu = %d", $fb_app->apikey, $fbu);
if ($user->uid || $user->uid == $fb_user_data['not_logged_in_uid'] || $user->uid == $fb_user_data['logged_in_uid']) {
db_query("INSERT INTO {fb_user_app} (apikey, fbu, uid, added, session_key, session_key_expires, time_cron, time_access, proxied_email) VALUES ('%s', %d, %d, 1, '%s', %d, %d, %d, '%s')",
$fb_app->apikey, $fbu,
$user->uid,
$fb->api_client->session_key, $fb->session_expires,
0, // time_cron
time(), // time_access
$proxied_email
);
}
else {
db_query("INSERT INTO {fb_user_app} (apikey, fbu, uid, added, session_key, session_key_expires, time_cron, time_access, proxied_email) VALUES ('%s', %d, %d, 1, '%s', %d, %d, %d, '%s')",
$fb_app->apikey, $fbu,
0, // uid not known
$fb->api_client->session_key, $fb->session_expires,
0, // time_cron
time(), // time_access
$proxied_email
);
}
}
else if ($event_type == FB_APP_EVENT_POST_REMOVE) {
// User has removed the app from their account.
// Should we delete the row here???
db_query("UPDATE {fb_user_app} SET added=0, session_key=NULL, session_key_expires=NULL WHERE apikey='%s' AND fbu=%d",
$fb_app->apikey, fb_facebook_user($fb));
}
}
}
function fb_user_form_alter(&$form, &$form_state, $form_id) {
// Add our settings to the fb_app edit form.
if (isset($form['fb_app_data'])) {
$node = $form['#node'];
$fb_user_data = _fb_user_get_config($node->fb_app);
$form['fb_app_data']['fb_user'] = array(
'#type' => 'fieldset',
'#title' => t('Facebook user settings'),
'#tree' => TRUE,
'#collapsible' => TRUE,
'#collapsed' => TRUE,
);
$form['fb_app_data']['fb_user']['create_account'] = array(
'#type' => 'radios',
'#title' => t('Create Local Account'),
'#description' => t('This option will create a local account automatically and create an entry in the authmap table. Choose never to use Drupal\'s built in user registration.'),
'#options' => array(
FB_USER_OPTION_CREATE_NEVER => t('Never (user/register page will still work)'),
FB_USER_OPTION_CREATE_LOGIN => t('If user has logged in'),
),
'#default_value' => $fb_user_data['create_account'],
'#required' => TRUE,
);
$form['fb_app_data']['fb_user']['map_account'] = array(
'#type' => 'radios',
'#title' => t('Map Accounts'),
'#description' => t('Mapping an account means creating an entry in the authmap table. This entry allows Drupal to know which Facebook id corresponds to which local uid.'),
'#options' => array(
FB_USER_OPTION_MAP_NEVER => t('Never map accounts'),
FB_USER_OPTION_MAP_ALWAYS => t('Map account when both local uid and Facebook id are known'),
),
'#default_value' => $fb_user_data['map_account'],
'#required' => TRUE,
);
$form['fb_app_data']['fb_user']['unique_account'] = array(
'#type' => 'checkbox',
'#title' => t('Make Account Mapping Unique (experimental, not recommended)'),
'#description' => t('If checked, the relationship between the local uid and the Facebook id applies only to this Application. This matters only when you host more than one application on this instance of Drupal.'),
'#default_value' => $fb_user_data['unique_account'],
);
// Choose a role to be granted to anyone who authorizes the app.
$form['fb_app_data']['fb_user']['new_user_rid'] = array(
'#type' => 'select',
'#title' => t('App user role'),
'#options' => user_roles(1),
'#description' => t('When a local user has authorized the app, the user will be granted this role.'),
'#default_value' => $fb_user_data['new_user_rid'],
);
// TODO: fix this so that it prompts for username with autocomplete, not a uid.
$form['fb_app_data']['fb_user']['not_logged_in_uid'] = array(
'#type' => 'textfield',
'#title' => t('Not authorized user (uid)'),
'#description' => t('If allowing non-logged in users, when such a user visits the site, which Drupal user should they be treated as? Use 0 for the anonymous user (recommended - this feature is experimental and likely to disappear).'),
'#default_value' => $fb_user_data['not_logged_in_uid'],
);
$form['fb_app_data']['fb_user']['logged_in_uid'] = array(
'#type' => 'textfield',
'#title' => t('Logged in user (uid)'),
'#description' => t('If allowing logged in users, when such a user visits the site, and they do not have a local Drupal account, which Drupal user should they be treated as? Use 0 for the Anonymous user (recommended - this feature is experimental and likely to disappear), or create a dedicated account for this purpose.'),
'#default_value' => $fb_user_data['logged_in_uid'],
);
}
else if ($form_id == 'user_edit' && ($app = $form['#fb_app'])) {
// Disable buttons on user/edit/app pages, nothing to submit
unset($form['submit']);
unset($form['delete']);
}
else if ($form_id == 'user_profile_form') {
// On user/edit, hide proxied email
if (isset($form['account']) && isset($form['account']['mail'])) {
$account = $form['_account']['#value'];
if (isset($account->fb_user_proxied_mail) &&
($form['account']['mail']['#default_value'] == $account->fb_user_proxied_mail)) {
unset($form['account']['mail']['#default_value']);
}
}
}
}
/**
* Learn the user's proxied email address.
* http://wiki.developers.facebook.com/index.php/Proxied_Email
*/
function fb_user_get_proxied_email($fbu, $fb_app) {
// Try to learn from local database
$result = db_query("SELECT * FROM {fb_user_app} WHERE apikey='%s' AND fbu=%d",
$fb_app->apikey,
$fbu);
if ($data = db_fetch_object($result)) {
$mail = $data->proxied_email;
}
if (!$mail) {
// Ask facebook for info.
$fb = fb_api_init($fb_app);
$info = fb_users_getInfo(array($fbu), $fb);
$data = $info[0];
$mail = $data['proxied_email'];
if ($mail) {
// Store locally.
$result = db_query("UPDATE {fb_user_app} SET proxied_email='%s' WHERE apikey='%s' AND fbu=%d",
$mail, $fb_app->apikey, $fbu);
}
}
return $mail;
}
/**
* Helper function for menu item access check.
*/
function fb_user_access_own($account, $perm, $allow_admin) {
if ($GLOBALS['user']->uid == $account->uid && user_access($perm)) {
return TRUE;
}
else if ($allow_admin) {
return user_access('administer users');
}
}
/**
* Implementation of hook_user.
*/
function fb_user_user($op, &$edit, &$account, $category = NULL) {
global $user;
static $apps;
// If form posted from an FBML canvas page, we learn the app and fbu from the post.
// TODO: do we need additional validation here? (i.e. an fb_api_init to confirm the facebook params?)
if (!empty($_REQUEST['fb_sig'])) {
//watchdog('debug', print_r($_REQUEST, 'fb_user_user request'));
$fb_app = fb_get_app(array('apikey' => $_REQUEST['fb_sig_api_key']));
$fbu = isset($_REQUEST['fb_sig_user']) ? $_REQUEST['fb_sig_user'] : NULL;
}
else if (!empty($GLOBALS['fb'])) {
// Post from iframe, or facebook connect page, or canvas page.
$fbu = fb_facebook_user();
$fb_app = $GLOBALS['fb_app'];
}
if (!empty($fb_app) && $op == 'load' && $account->uid) {
if (!$account->mail) {
// Use proxied email, if facebook app is active and user uses it.
// TODO: confirm drupal never saves proxied address to users.mail.
$account->mail = fb_user_get_proxied_email($fbu, $fb_app);
$account->fb_user_proxied_mail = $account->mail; // Remember where we got address.
}
}
if (!empty($fb_app) && $op == 'insert' || $op == 'login') {
// A facebook user has logged in. We can map the two accounts together.
$fb_user_data = _fb_user_get_config($fb_app);
if ($fbu &&
$fb_user_data['map_account'] == FB_USER_OPTION_MAP_ALWAYS) {
list($module, $authname) = _fb_user_get_authmap($fb_app, $fbu);
if ($op == 'insert') {
// New user, we set up the authmap this way...
$edit['authname_fb_user'] = $authname;
}
else if ($op == 'login') {
// Existing user, we set up the map this way...
user_set_authmaps($account, array($module => $authname));
}
// TODO: if the app has a role, make sure the user gets that role. (presently, that will not happen until their next request)
}
}
// Add tabs on user edit pages to manage maps between local accounts and facebook accounts.
if ($op == 'categories') {
// A tab allowing authmaps to be changed.
$items[] = array('name' => 'fb_user',
'title' => t('Facebook Applications'),
'access callback' => 'fb_user_access_own',
'access arguments' => array(1, 'delete own fb_user authmap', TRUE),
'weight' => 1,
);
return $items;
}
else if ($op == 'form' && $category == 'fb_user') {
if (!user_access('administer users') &&
!(user_access('delete own fb_user authmap') && $user->uid == $account->uid))
return; // hide from this user
// Iterate through all facebook apps, because they do not all use the same
// map scheme.
$result = _fb_app_query_all();
while ($fb_app = db_fetch_object($result)) {
$fb_user_data = _fb_user_get_config($fb_app);
$fbu = _fb_user_get_fbu($account->uid, $fb_app);
if ($fbu && !$info[$fbu]) {
// The drupal user is a facebook user. Now, learn more from facebook.
$fb = fb_api_init($fb_app, FB_FBU_ANY);
// Note: this requires infinite session with facebook or active fbconnect session. TODO: fallback to fb_user_app table.
$info[$fbu] = $fb->api_client->users_getInfo(array($fbu),
array('name',
'is_app_user',
));
}
if ($fbu) {
list($module, $authname) = _fb_user_get_authmap($fb_app, $fbu);
if ($fb_user_data['unique_account']) {
$form['map'][$module] = array('#type' => 'checkbox',
'#title' => $fb_app->title,
'#default_value' => $authname,
'#return_value' => $authname,
);
}
else {
$shared_maps[] = $fb_app->title;
$shared_fbu = $fbu; // Same for all shared apps.
$shared_module = $module;
$shared_authname = $authname;
}
}
if ($shared_maps) {
$form['map'][$shared_module] = array('#type' => 'checkbox',
'#title' => implode('
', $shared_maps),
'#default_value' => $shared_authname,
'#return_value' => $shared_authname,
);
if ($info[$shared_fbu]) {
$data = $info[$shared_fbu][0];
$fb_link = l($data['name'], 'http://www.facebook.com/profile.php',
array('query' => array('id' => $data['uid'])));
$form['map'][$shared_module]['#description'] .= t('Local account !username corresponds to !profile_page on Facebook.com.',
array('!username' => l($account->name, 'user/' . $account->uid),
'!profile_page' => $fb_link));
}
}
if (!$fbu) {
if ($user->uid == $account->uid) {
// TODO: give a user a way to map their facebook account to their local account.
}
else {
$form[$fb_app->nid] = array('#type' => 'markup',
'#value' => t('!username does not use !application.',
array('!username' => theme('username', $account),
'!application' => l($fb_app->title, 'node/'.$fb_app->nid),
)),
'#prefix' => "\n
", '#suffix' => "
\n", ); } } } if (isset($form)) { $form['map']['#tree'] = TRUE; } else { // Could add a facebook connect button or canvas page authorization link. $form['description'] = array( '#type' => 'markup', '#value' => t('This account is not associated with a Facebook Application.'), '#prefix' => '', '#suffix' => '
', ); } return $form; } else if ($op == 'update' && $category == 'fb_user') { if (is_array($edit['map'])) { foreach ($edit['map'] as $module => $authname) { user_set_authmaps($account, array($module => $authname)); } } } else if ($op == 'delete') { db_query("DELETE FROM {fb_user_app} WHERE uid=%d", $account->uid); } } /** * Helper function to create an authname for the authmap table. * * When a single Drupal instance hosts multiple Facebook apps, the apps can * share the same mapping, or each have their own. * * @return an array with both a 'module' and an authname. A * data structure necessary for Drupal's authmap api. */ function _fb_user_get_authmap($fb_app, $fbu) { $fb_user_data = _fb_user_get_config($fb_app); $app_specific = $fb_user_data['unique_account']; // map fbu to uid, include apikey if user is app_specific if ($app_specific) { // would rather use the shorter app id (not apikey), but no way to query it $authname = "$fbu-$fb_app->apikey@facebook.com"; $module = "authname_fb_user-$fb_app->nid"; } else { $authname = "$fbu@facebook.com"; $module = "authname_fb_user"; } //return array('module' => $module, 'authname' => $authname); return array($module, $authname); } /** * Helper function to keep the authmap table in sync. */ function _fb_user_set_authmap($fb_app, $fbu, $account) { $fb_user_data = _fb_user_get_config($fb_app); if ($fb_user_data['map_account'] == FB_USER_OPTION_MAP_ALWAYS && $fbu && $account->uid != 0 && $account->uid != $fb_user_data['logged_in_uid']) { list($module, $authname) = _fb_user_get_authmap($fb_app, $fbu); user_set_authmaps($account, array($module => $authname)); if (fb_verbose()) { watchdog('fb_user', 'Using authmap to associate user !user with facebook user id %fbu.', array('!user' => l($account->name, 'user/' . $account->uid), '%fbu' => $fbu, )); } } } /** * Creates a local Drupal account for the specified facebook user id. * * @param fbu * The facebook user id corresponding to this account. * * @param edit * An associative array with user configuration. As would be passed to user_save(). */ function fb_user_create_local_user($fb, $fb_app, $fbu, $edit = array()) { // Ensure $fbu is a real facebook user id. if (!$fbu || !is_numeric($fbu)) { return; } list($module, $authname) = _fb_user_get_authmap($fb_app, $fbu); $account = user_external_load($authname); if (!$account) { // Create a new user in our system // Learn some details from facebook. $infos = fb_users_getInfo(array($fbu), $fb); $info = $infos[0]; // All Drupal users get authenticated user role. $edit['roles'][DRUPAL_AUTHENTICATED_RID] = 'authenticated user'; // Ensure unique username. Append "_N" if necessary. if (isset($edit['name']) && $edit['name']) { $username = $edit['name']; } else { $username = "$fbu@facebook"; $edit['name'] = $username; } $i = 1; while (db_result(db_query("SELECT name FROM {users} WHERE name='%s'", $edit['name']))) { $i++; $edit['name'] = $username . '_' . $i; } // Allow third-party module to adjust any of our data before we create // the user. $edit = fb_invoke(FB_OP_PRE_USER, array('fbu' => $fbu, 'fb' => $GLOBALS['fb'], 'fb_app' => $fb_app, 'info' => $info), $edit); // Fill in any default that are missing. $defaults = array( 'pass' => user_password(), 'init' => db_escape_string($edit['name']), 'status' => 1, 'authname_fb_user' => $authname, // authmap entry ); // Mail available only if user has granted extended permission. if (isset($info['email']) && ($info['email'] != $info['proxied_email'])) { $defaults['mail'] = $info['email']; } // Merge defaults $edit = array_merge($defaults, $edit); // Confirm username is not taken. FB_OP_PRE_USER may have changed it. if ($uid = db_result(db_query("SELECT uid FROM {users} WHERE name='%s'", $user_data_sanitized['name']))) { // The desired name is taken. watchdog('fb_user', 'Failed to create new user %name. That name is already in the users table.', array('%name' => $user_data_sanitized['name']), WATCHDOG_ERROR, l(t('view user'), 'user/' . $uid)); } else { $account = user_save('', $edit); watchdog('fb_user', 'New user: %name %email.', array('%name' => $account->name, '%email' => '<'. $account->mail .'>'), WATCHDOG_NOTICE, l(t('edit'), 'user/'. $account->uid .'/edit')); // Allow third-party modules to act after account creation. fb_invoke(FB_OP_POST_USER, array('account' => $account, 'fb_app' => $fb_app, 'fb' => $fb)); } } return $account; } /** * Given an app and facebook user id, return the corresponding local user. */ function fb_user_get_local_user($fbu, $fb_app) { // TODO: this function should probably use user_external_load, rather than query the database directly. See deprecated fb_user_load for example. // TODO: this query probably needs to search for one authname or the other, not both. // Alternately, use the fb_user_app table rather than authmap to look up this information. $result = db_query("SELECT am.* FROM authmap am WHERE am.authname='%s' OR am.authname='%s' ORDER BY am.authname", "$fbu-$fb_app->apikey@facebook.com", "$fbu@facebook.com"); if ($data = db_fetch_object($result)) { $account = user_load(array('uid' => $data->uid)); return $account; } } /** * Returns local uids of friends of a given user. * * Query is relatively efficient for the current user of a canvas page. For * all other users, and non-canvas pages it requires expensive call to * facebook. That said, our local database query may be inefficient for users * with large numbers of friends, so use with caution. * * TODO: should this function cache results? * * Note: the api takes fbu as a parameter, but this usually causes problems * because facebook restricts users to query only about their own friends. * For the time being, expect this function to work only on canvas pages to * find friends of the current user. */ function fb_user_get_local_friends($fbu = NULL, $fb_app = NULL) { if (!isset($fbu)) { $fbu = fb_facebook_user(); } $uids = array(); if ($fbus = fb_get_friends($fbu, $fb_app)) { // Should this query be limited to users of the app? $query = "SELECT uid FROM {fb_user_app} WHERE fbu in (%s) AND uid>0"; $args[] = implode(',', $fbus); $result = db_query($query, $args); while ($data = db_fetch_object($result)) { if ($data->uid) { $uids[] = $data->uid; } } } return $uids; } /** * Given a local user id, find the facebook id. This is for internal use. * Outside modules use fb_get_fbu(). */ // TODO: change this to use the newly added uid column in fb_user_app table. function _fb_user_get_fbu($uid, $fb_app) { static $cache = array(); if (!isset($cache[$uid])) { $cache[$uid] = array(); // Look up this user in the authmap $result = db_query("SELECT * FROM {authmap} WHERE uid=%d AND authname LIKE '%@facebook.com'", $uid); while (!isset($fbu) && $data = db_fetch_object($result)) { // get the part before the '@' $substr = substr($data->authname, 0, strpos($data->authname, '@')); // then split at the '-' $parts = explode('-', $substr); if (isset($parts[1])) // $parts[1] is app id $cache[$uid][$parts[1]] = $parts[0]; else $cache[$uid]['global'] = $parts[0]; } } // Return either the global or the app-specific mapping, depending on the app configuration. $fb_user_data = _fb_user_get_config($fb_app); if ($fb_user_data['unique_account']) // Return the app-specific mapping return $cache[$uid][$fb_app->apikey]; else if (isset($cache[$uid]['global'])) // Return the global mapping return $cache[$uid]['global']; } function fb_user_token_list($type = 'all') { if ($type == 'all' || $type == 'fb' || $type == 'fb_app') { $tokens['fb_app']['fb-app-user-fbu'] = t('Current user\'s Facebook ID'); $tokens['fb_app']['fb-app-user-name'] = t('Current user\'s name on Facebook (TODO)'); $tokens['fb_app']['fb-app-user-name-fbml'] = t('Current user\'s name for display on Facebook profile and canvas pages.'); $tokens['fb_app']['fb-app-profile-url'] = t('Current user\'s Facebook profile URL'); } return $tokens; } function fb_user_token_values($type = 'all', $object = NULL) { $values = array(); if ($type == 'fb_app' && $object) { $fb_app = $object; global $user; $fbu = _fb_user_get_fbu($user->uid, $fb_app); if ($fbu) { $values['fb-app-user-fbu'] = $fbu; $values['fb-app-user-name'] = 'TODO XXX'; $values['fb-app-user-name-fbml'] = '