fb_user_app.module in Drupal for Facebook 7.3
Same filename and directory in other branches
This module manages relations between local Drupal user accounts and their accounts on facebook.com by application.
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
contrib/fb_user_app.moduleView source
<?php
/**
* @file
* This module manages relations between local Drupal user accounts
* and their accounts on facebook.com by application.
*
* 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_APP_VAR_TRACK_EVERY_PAGE', 'fb_user_app_track_every_page');
define('FB_USER_APP_VAR_USERS_THAT_GRANT_OFFLINE', 'fb_user_app_users_that_grant_offline');
define('FB_USER_APP_VAR_TRACK_USERS', 'fb_user_app_track_users');
define('FB_USER_APP_VAR_TRACK_PAGES', 'fb_user_app_track_pages');
//// Menu structure.
/**
* Implementation of hook_menu().
*/
function fb_user_app_menu() {
$items = array();
// Admin pages overview.
$items[FB_PATH_ADMIN . "/fb_user_app"] = array(
'title' => 'Tracking',
'description' => 'Settings that track statistics in Drupal for Facebook',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'fb_user_app_admin_settings',
),
'access arguments' => array(
FB_PERM_ADMINISTER,
),
'file' => 'fb_user_app.admin.inc',
'type' => MENU_LOCAL_TASK,
);
return $items;
}
/**
* Implementation of hook_fb()
*/
function fb_user_app_fb($op, $data, &$return) {
$fb_app = isset($data['fb_app']) ? $data['fb_app'] : NULL;
$fb = isset($data['fb']) ? $data['fb'] : NULL;
global $user;
if ($op == FB_OP_APP_IS_AUTHORIZED && variable_get(FB_USER_APP_VAR_TRACK_EVERY_PAGE, FALSE)) {
// This hook is called on every page request, if the user has authorized
// the app/page and permission has been granted in the settings. We used
// to create accounts and maps here. That code is now
// in FB_OP_AJAX_EVENT, because it turns out this hook is invoked even on
// page not found and access denied pages.
fb_user_app_track($fb, $fb_app, $user);
}
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) {
// Track new facebook user, $GLOBAL['user'] not valid during post-authorize.
fb_user_app_track($fb, $fb_app);
}
elseif ($event_type == FB_APP_EVENT_POST_REMOVE) {
$fbu = fb_settings(FB_SETTINGS_FBU);
// User has removed the app from their account.
db_query("DELETE FROM {fb_user_app} WHERE apikey=:apikey AND fbu=:fbu", array(
':apikey' => $fb_app->apikey,
':fbu' => $fbu,
));
}
}
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 = :apikey and fbu = :fbu", array(
':apikey' => $fb_app->apikey,
':fbu' => $fbu,
));
$data = $result
->fetchObject();
if ($data && $data->session_key) {
// Return array with FB id and apikey.
$return = array(
'fbu' => $data->fbu,
'access_token' => $data->session_key,
'expires' => $data->session_key_expires,
);
}
}
elseif ($op == FB_OP_AJAX_EVENT) {
// handle internal login
// @TODO - global user is not correct here.
// fb.js has notified us of an event via AJAX. Not the same as facebook event callback above.
if ($data['event_type'] == 'session_change' && isset($data['event_data']['fbu'])) {
// A user has logged in.
fb_user_app_track($fb, $fb_app, $user);
}
}
}
/**
* Implements hook_user_delete().
*
* @TODO confirm there is no race condition between this module and fb_user.
* That is, during delete, does fb_get_fbu() still work?
*/
function fb_user_app_user_delete($account) {
// Given the uid, fetch the fbu so that we can delete
$fbu = fb_get_fbu($account->uid);
db_query('DELETE FROM {fb_user_app} WHERE fbu=:fbu', array(
':fbu' => $fbu,
));
}
/**
* Keep track of when the user has visited the app.
*
* Historically we could learn a user's ID even if they hadn't authorized
* ("added") the app. No longer the case, so all entries in fb_user_app
* should be for authorized users.
*
* A "signed request" should be fully-formed (have an oauth_token) on canvas
* pages, and on post authorize events (for as long as facebook continues to
* support them). So this tracking will work best for canvas page apps and
* less reliably for connect.
*/
function fb_user_app_track($fb, $fb_app) {
// Coming from a user adding the app or a page adding the app?
$fb_user_type = "user";
$fbu = fb_facebook_user($fb);
if (array_key_exists('fb_sig_page_added', $_REQUEST)) {
// It's a post-authorize event for app added to page.
$fb_user_type = "page";
$fbu = $_REQUEST['fb_sig_page_id'];
}
$sr = $fb
->getSignedRequest();
//watchdog('fb_user_app', __FUNCTION__ . " signed request is <pre>" . print_r($sr,1) . "</pre>"); // debug
if (isset($sr['oauth_token'])) {
$access_token = $sr['oauth_token'];
$expires = $sr['expires'];
$fbu = $sr['user_id'];
}
else {
// @TODO: with new SDK, is there any useful tracking info?
return;
}
// when 'expires' == 0 app has been granted offline access
if ($fb_user_type == 'user' && $expires != 0 && variable_get(FB_USER_APP_VAR_USERS_THAT_GRANT_OFFLINE, FALSE)) {
// Note, with new SDK, facebook provides 'expires' date even when user HAS GRANTED offline_access!
// @TODO: find some way to tell whether an access token will actually expire!
return;
}
// Track this event only if allowed to and only for users, not pages
if (variable_get(FB_USER_APP_VAR_TRACK_USERS, TRUE) && ($fb_user_type = "user") || variable_get(FB_USER_APP_VAR_TRACK_PAGES, TRUE) && ($fb_user_type = "page")) {
$result1 = db_query("UPDATE {fb_user_app} SET time_access=:time, session_key=:token, session_key_expires=:expires, user_type=:type WHERE apikey=:apikey AND fbu=:fbu", array(
':time' => REQUEST_TIME,
':token' => $access_token,
':expires' => $expires,
':type' => $fb_user_type,
':apikey' => $fb_app->id,
':fbu' => fb_facebook_user($fb),
));
if ($result1 && $result1
->rowCount() == 0) {
// The row for this user was never inserted, or it was deleted, or the times were the same.
$fbu = fb_facebook_user($fb);
if ($fbu) {
// First make sure it was not just the same time
$result = db_query("SELECT * FROM {fb_user_app} WHERE apikey=:apikey AND fbu=:fbu", array(
':apikey' => $fb_app->apikey,
':fbu' => $fbu,
));
if (!$result
->fetchObject()) {
//This row does not exist, even with the same time. Insert now
list($data) = fb_fql_query($fb, "SELECT name, is_app_user, email, proxied_email FROM user WHERE uid={$fbu}", array(
'access_Token' => $fb_session_key,
));
//watchdog('fb_user_app', "fb user data <pre>" . print_r($data, 1) . '</pre>');
$fb_user_type = "user";
$result = db_query("INSERT INTO {fb_user_app} (apikey, fbu, added, user_type, session_key, session_key_expires, time_access, proxied_email, time_cron) VALUES (:apikey, :fbu, :added, :user_type, :session_key, :session_key_expires, :time_access, :proxied_email, :time_cron)", array(
':apikey' => $fb_app->apikey,
':fbu' => $fbu,
':added' => $data['is_app_user'],
':user_type' => $fb_user_type,
':session_key' => $access_token,
':session_key_expires' => $expires,
':time_access' => REQUEST_TIME,
':proxied_email' => $data['email'] ? $data['email'] : ($data['proxied_email'] ? $data['proxied_email'] : ''),
// test accounts will not have
':time_cron' => 0,
));
}
}
}
if (FALSE && $result === FALSE) {
// XXX upgrade to D7???
watchdog('fb_user_app', "Failed to update fb_user_app table.", array(), WATCHDOG_ERROR);
}
}
}
/**
* Learn the user's proxied email address.
*
*/
function fb_user_app_get_proxied_email($fbu, $fb_app) {
// Try to learn from local database
$result = db_query("SELECT * FROM {fb_user_app} WHERE apikey=:apikey AND fbu=:fbu", array(
':apikey' => $fb_app->apikey,
':fbu' => $fbu,
));
if ($data = $result
->fetchObject()) {
$mail = $data->proxied_email;
}
if (!isset($mail) || !$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_APP_VAR_TRACK_USERS, TRUE)) {
// Store locally.
$result = db_query("UPDATE {fb_user_app} SET proxied_email=:mail WHERE apikey=:apikey AND fbu=:fbu", array(
':mail' => $mail,
':apikey' => $fb_app->apikey,
':fbu' => $fbu,
));
}
}
return $mail;
}
Functions
Name | Description |
---|---|
fb_user_app_fb | Implementation of hook_fb() |
fb_user_app_get_proxied_email | Learn the user's proxied email address. |
fb_user_app_menu | Implementation of hook_menu(). |
fb_user_app_track | Keep track of when the user has visited the app. |
fb_user_app_user_delete | Implements hook_user_delete(). |
Constants
Name | Description |
---|---|
FB_USER_APP_VAR_TRACK_EVERY_PAGE | @file This module manages relations between local Drupal user accounts and their accounts on facebook.com by application. |
FB_USER_APP_VAR_TRACK_PAGES | |
FB_USER_APP_VAR_TRACK_USERS | |
FB_USER_APP_VAR_USERS_THAT_GRANT_OFFLINE |