fb_user.module in Drupal for Facebook 6.2
Same filename and directory in other branches
This module manages relations between local Drupal user accounts and their accounts on facebook.com.
This module can create a new local user account, when a facebook user authorizes an application hosted on this server.
Links existing local accounts to remote accounts on facebook via Drupal's authmap table.
Drupal refers to a local user id as 'uid'. Facebook's documentation and code also uses 'uid'. In these modules we use 'fbu' for facebook's id and 'uid' for Drupal's id.
File
fb_user.moduleView source
<?php
/**
* @file
* This module manages relations between local Drupal user accounts
* and their accounts on facebook.com.
*
* This module can create a new local user account, when a facebook
* user authorizes an application hosted on this server.
*
* Links existing local accounts to remote accounts on facebook via
* Drupal's authmap table.
*
* Drupal refers to a local user id as 'uid'. Facebook's documentation
* and code also uses 'uid'. In these modules we use 'fbu' for facebook's
* id and 'uid' for Drupal's id.
*/
define('FB_USER_OPTION_CREATE_NEVER', 1);
define('FB_USER_OPTION_CREATE_LOGIN', 2);
define('FB_USER_OPTION_MAP_NEVER', 1);
define('FB_USER_OPTION_MAP_ALWAYS', 2);
define('FB_USER_VAR_STATS', 'fb_user_stats');
// Whether to use fb_user_app table.
/**
* Implementation of hook_perm().
*/
function fb_user_perm() {
return array(
'delete own fb_user authmap',
);
}
/**
* Implementation of hook_menu().
*/
function fb_user_menu() {
$items = array();
// Admin pages
$items[FB_PATH_ADMIN . '/fb_user'] = array(
'title' => 'User Management',
'description' => 'Local account to facebook account mapping',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'fb_user_admin_settings',
),
'access arguments' => array(
FB_PERM_ADMINISTER,
),
'file' => 'fb_user.admin.inc',
'type' => MENU_LOCAL_TASK,
);
return $items;
}
/**
* Returns configuration for this module, on a per-app basis.
*/
function _fb_user_get_config($fb_app) {
$fb_app_data = fb_get_app_data($fb_app);
$fb_user_data = $fb_app_data['fb_user'] ? $fb_app_data['fb_user'] : array();
// Merge in defaults
$fb_user_data += array(
'create_account' => FB_USER_OPTION_CREATE_NEVER,
'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.
*
* Historically this supported infinite sessions. I believe if this data is
* no longer necessary for the offline access extended permission.
*/
function _fb_user_track($fb, $fb_app, $account) {
if (variable_get(FB_USER_VAR_STATS, TRUE)) {
// 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);
}
}
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.
$account = fb_user_get_local_user($fbu, $fb_app);
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_LOGIN && $fb->api_client
->users_isAppUser()) {
// We need to make a local account for this facebook user.
// A name that is likely to be unique.
$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) {
// Still necessary???
// 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 (variable_get(FB_USER_VAR_STATS, TRUE)) {
// 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(), $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, $fb->api_client->session_key, $fb->session_expires, 0, time(), $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 and an entry in the authmap table when a user authorizes a canvas page or connects using Facebook Connect. If not, Drupal\'s built in user registration will still work.'),
'#options' => array(
FB_USER_OPTION_CREATE_NEVER => t('Do not create accounts automatically'),
FB_USER_OPTION_CREATE_LOGIN => t('If user has authorized the app'),
),
'#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,
);
// 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 && variable_get(FB_USER_VAR_STATS, TRUE)) {
// 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);
$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'] ? $data['name'] : $fbu, '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,
)),
'#prefix' => "\n<p>",
'#suffix' => "</p>\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' => '<p>',
'#suffix' => '</p>',
);
}
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);
$authname = $fbu;
$module = "authname_fb_user";
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 = fb_user_get_local_user($fbu, $fb_app);
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,
);
// 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.
*
* Prefer this to user_external_load(), because that does not honor the module column.
*/
function fb_user_get_local_user($fbu, $fb_app) {
// Priority to app-specific map.
$result = db_result(db_query("SELECT uid FROM {authmap} WHERE authname='%s' AND module='%s'", array(
$fbu,
'fb_user_' . $fb_app->label,
)));
if (!$result) {
// non app-specific
$result = db_result(db_query("SELECT uid FROM {authmap} WHERE authname='%s' AND module='%s'", array(
$fbu,
'fb_user',
)));
}
if ($result) {
return user_load($result);
}
}
/**
* 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.
*
* Only works if the "map accounts" feature is enabled.
*/
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"; // old way, using fb_user_app
$query = "SELECT uid FROM {authmap} WHERE authname IN ('%s') AND module='%s'";
// better? way using authmap.
$args[] = implode(',', $fbus);
$args[] = 'fb_user';
$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().
*
* Only works if the "map accounts" feature is enabled.
*/
function _fb_user_get_fbu($uid, $fb_app) {
static $cache = array();
// cache to avoid excess queries.
if (!isset($cache[$uid])) {
// Look up this user in the authmap
$result = db_result(db_query("SELECT authname FROM {authmap} WHERE uid=%d AND module='%s'", array(
$uid,
'fb_user',
)));
if ($result) {
$cache[$uid] = $result;
}
}
if (isset($cache[$uid])) {
return $cache[$uid];
}
}
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'] = '<fb:name uid="' . $fbu . '" />';
$values['fb-app-profile-url'] = 'http://www.facebook.com/profile.php?id=' . $fbu;
}
}
return $values;
}
Functions
Name | Description |
---|---|
fb_user_access_own | Helper function for menu item access check. |
fb_user_create_local_user | Creates a local Drupal account for the specified facebook user id. |
fb_user_fb | Implementation of hook_fb. |
fb_user_form_alter | |
fb_user_get_local_friends | Returns local uids of friends of a given user. |
fb_user_get_local_user | Given an app and facebook user id, return the corresponding local user. |
fb_user_get_proxied_email | Learn the user's proxied email address. http://wiki.developers.facebook.com/index.php/Proxied_Email |
fb_user_menu | Implementation of hook_menu(). |
fb_user_perm | Implementation of hook_perm(). |
fb_user_token_list | |
fb_user_token_values | |
fb_user_user | Implementation of hook_user. |
_fb_user_get_authmap | Helper function to create an authname for the authmap table. |
_fb_user_get_config | Returns configuration for this module, on a per-app basis. |
_fb_user_get_fbu | Given a local user id, find the facebook id. This is for internal use. Outside modules use fb_get_fbu(). |
_fb_user_set_authmap | Helper function to keep the authmap table in sync. |
_fb_user_special_page | There are several pages where we don't want to automatically create a new account or use an account configured for this app. |
_fb_user_track | Keep track of when the user has visited the app, and whether they've authorized the app or not. |
Constants
Name | Description |
---|---|
FB_USER_OPTION_CREATE_LOGIN | |
FB_USER_OPTION_CREATE_NEVER | @file This module manages relations between local Drupal user accounts and their accounts on facebook.com. |
FB_USER_OPTION_MAP_ALWAYS | |
FB_USER_OPTION_MAP_NEVER | |
FB_USER_VAR_STATS |