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']; } elseif (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 } } } } elseif ($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); } elseif ($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); } elseif ($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); } elseif ($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 ); } } elseif ($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'])) { $fb_app = $form['#fb_app']; $fb_user_data = _fb_user_get_config($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'], ); } elseif ($form_id == 'user_edit' && ($app = $form['#fb_app'])) { // Disable buttons on user/edit/app pages, nothing to submit unset($form['submit']); unset($form['delete']); } elseif ($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; } elseif ($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; } elseif (!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; } elseif ($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; } elseif ($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 // necessarily use the same map scheme. $apps = fb_get_all_apps(); foreach ($apps as $fb_app) { $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->label, '#default_value' => $authname, '#return_value' => $authname, ); } else { $shared_maps[] = $fb_app->label; $shared_fbu = $fbu; // Same for all shared apps. $shared_module = $module; $shared_authname = $authname; } } if ($shared_maps) { // One authmap entry applies to more than on app. $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->label] = array( '#type' => 'markup', '#value' => t('!username does not use !application.', array('!username' => theme('username', $account), '!application' => $fb_app->label, // TODO: show real name and link to facebook page. )), '#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; } elseif ($op == 'update' && $category == 'fb_user') { if (is_array($edit['map'])) { foreach ($edit['map'] as $module => $authname) { user_set_authmaps($account, array($module => $authname)); } } } elseif ($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]; elseif (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'; // XXX $values['fb-app-user-name-fbml'] = '