');
foreach ($apps as $app) {
$options[$app->nid] = $app->title;
}
return $options;
}
/**
* Convenience method to return array of all know fb_apps.
*/
function fb_get_all_apps() {
$apps = _fb_invoke(NULL, FB_OP_GET_ALL_APPS, array());
return $apps;
}
// return array of facebook uids
function fb_get_friends($fbu) {
static $cache = array();
global $fb;
if (!$fb || !$fbu)
return;
if (!isset($cache[$fbu])) {
if ($fbu == fb_facebook_user())
$items = $fb->api_client->friends_get();
// friends_get does not work in cron call, so we double check.
if (!$items || !count($items)) {
$result = $fb->api_client->fql_query("SELECT uid2 FROM friend WHERE uid1=$fbu");
$items = array();
if (count($result))
foreach ($result as $data) {
$items[] = $data['uid2'];
}
}
// Facebook's API has the annoying habit of returning an item even if user
// has no friends. We need to clean that up.
if (!$items[0])
unset($items[0]);
$cache[$fbu] = $items;
}
return $cache[$fbu];
}
// Return array of facebook gids
function fb_get_groups($fbu) {
$items = array();
$groups = fb_get_groups_data($fbu);
if ($groups && count($groups))
foreach ($groups as $data) {
$items[] = $data['gid'];
}
return $items;
}
function fb_get_groups_data($fbu) {
static $cache = array();
global $fb;
if (!$fb || !$fbu)
return;
if (!isset($cache[$fbu])) {
$cache[$fbu] = $fb->api_client->groups_get($fbu, NULL);
}
return $cache[$fbu];
}
// deprecated since creation of fb_user module, but cron hook still uses this.
function fb_user_load($fbu = NULL) {
global $user;
if (!$fbu)
// default to current logged in user
$fbu = fb_facebook_user();
if ($fbu && $user->fbu == $fbu) {
return $user;
}
if ($fbu) {
$account = user_external_load("$fbu-$fb_app->apikey@facebook.com");
if (!$account)
$account = user_external_load("$fbu@facebook.com");
if (!$account)
$account = user_load(array('uid' => variable_get('fb_facebook_user', 2)));
if (!$account)
watchdog('fb', t('Failed to load user from facebook fbu=%fbu',
array('%fbu' => $fbu)), 'error');
$account->fbu = $fbu;
return $account;
}
}
function fb_form_alter($form_id, &$form) {
// We will send all form submission directly to us, not via
// app.facebook.com/whatever. Since we've tricked drupal into writing our
// URLs as if we were there, we need to untrick the form action.
if ($_REQUEST['fb_sig']) {
global $fb_app;
// We're in a facebook callback
if ($form['#action'] == '') {
$form['#action'] = $_GET['q'];
}
else {
}
$form['#action'] = _fb_make_form_action_local($form['#action']);
// Let's hope no subsequent hook_form_alters mess with #action.
}
// Because facebook users don't have email, it can't be required on user form
if ($form_id == 'user_register') {
if (user_access('administer users')) {
$form['mail']['#required'] = FALSE;
}
}
if ($form_id == 'user_edit') {
if (user_access('administer users')) {
$form['account']['mail']['#required'] = FALSE;
}
}
}
function fb_menu($may_cache) {
$items = array();
if (!$may_cache) {
// Initialization moved to fb_init(), nothing to do here.
}
else {
// When forms are submitted directly to us, we cache the results,
// and show them later via this callback
$items[] = array('path' => 'fb/form_cache',
'callback' => '_fb_form_cache_cb',
'type' => MENU_CALLBACK,
'access' => TRUE);
// A page to help determine infinite session keys
$items[] = array('path' => 'fb/session',
'callback' => '_fb_session_cb',
'type' => MENU_CALLBACK,
'access' => TRUE); // TODO: restrict access?
$items[] = array('path' => 'fb/debug',
'callback' => '_fb_debug_cb',
'type' => MENU_CALLBACK,
'access' => TRUE, // TODO: restrict access
);
}
return $items;
}
/**
* When exiting we need to do some special stuff for forms
*/
function fb_exit($destination = NULL) {
global $fb_app, $fb;
_fb_invoke($fb_app, FB_OP_EXIT);
if (_fb_handling_form()) {
$output = ob_get_contents();
ob_end_clean();
if ($destination) {
// Destination is set when a node is submitted, for example.
// just let the redirect happen
return;
}
// Save the results to show the user later
$token = uniqid('fb_');
$cid = session_id() . "_$token";
watchdog('fb', "Storing cached form page $cid, then redirecting");
cache_set($cid, 'cache_page', $output, time() + (60 * 5), drupal_get_headers()); // (60 * 5) == 5 minutes
$dest = 'http://apps.facebook.com/' . $fb_app->canvas."/fb/form_cache/$cid";
// $fb->redirect($url); // Does not work!
drupal_goto($dest,'', NULL, 303); // appears to work
}
if ($destination) {
// If here, drupal_goto has been called, but it may not work within a
// canvase page, so we'll use Facebook's method.
// Will this preempt other hook_exits?
if ($fb) {
$fb->redirect($destination);
}
}
}
function _fb_form_cache_cb($cid) {
// Facebook started appending a '?', we need to get rid of it.
if ($pos = strpos($cid, '?'))
$cid = substr($cid, 0, $pos);
watchdog('fb', "Returning cached form page $cid");
$cache = cache_get($cid, 'cache_page');
// Don't clear, as user may refresh browser. Cache will expire eventually.
// cache_clear_all($cid, 'cache_page');
print $cache->data;
exit();
}
function _fb_session_cb() {
global $fb, $fb_app;
global $user;
drupal_set_message("_fb_session_cb" . dpr($_REQUEST, 1));
$output = ''.t('You are logged in as local user !username, with Facebook user id %fbu.',
array('!username' => theme('username', $user),
'%fbu' => fb_get_fbu($user))).'
';
$output .= ''.l(t('Request an infinite session key.'),
'http://www.facebook.com/code_gen.php?v=1.0&api_key='.$fb_app->apikey).'
';
$output .= drupal_get_form('fb_session_key_form');
$output .= ''.t('Current session key: %key',
array('%key' => htmlentities($fb->api_client->session_key)))."
\n";
return $output;
}
function fb_session_key_form() {
global $fb_app;
$form = array('auth_token' => array('#type' => 'textfield',
'#title' => t('One-time code'),
'#description' => t('If you do not have a one-time code, you can get one !here.',
array('!here' => l(t('here'), 'http://www.facebook.com/code_gen.php?v=1.0&api_key='.$fb_app->apikey))),
),
'submit' => array('#type' => 'submit',
'#value' => t('Submit')),
'#redirect' => FALSE, // necessary when submitting via facebook
);
return $form;
}
/**
* Provides a page with useful debug info.
*
* TODO: remove dependencies on devel package.
*/
function _fb_debug_cb() {
global $fb, $fb_app;
global $user;
if ($fb) {
// These will work in a canvas page.
drupal_set_message("in_fb_canvas returns " . $fb->in_fb_canvas());
drupal_set_message("get_loggedin_user returns " . $fb->get_loggedin_user());
drupal_set_message("current_url returns " . $fb->current_url());
}
dpm(fb_get_fbu($user), 'Facebook user via fb_get_fbu');
dpm($user, "Local user " . theme('username', $user));
dpm($_REQUEST, "Request");
dpm($fb_app, "fb_app");
dpm($fb->api_client->session_key, "session key ");
//watchdog('fb_debug', 'debug callback called. Request is ' . dpr($_REQUEST, 1));
return "This is the facebook debug page.";
}
function _fb_invoke($fb_app, $op, $return = NULL, $data = NULL) {
global $fb;
foreach (module_implements(FB_HOOK) as $name) {
$function = $name . '_' . FB_HOOK;
$function($fb, $fb_app, $op, $return, $data);
}
return $return;
}
/**
* Implementation of hook_node_grants.
*
* We put this here so all facebook modules have a standard way to implement
* hook_node_access_records. They use that hook to insert records into the
* node access table. We use this hook to allow access when the grants are
* there.
*/
function fb_node_grants($account, $op) {
$grants = array();
$fbu = fb_get_fbu($account);
if ($fbu) { // If not anonymous (facebook user not logged in to this app)
$friends = fb_get_friends($fbu);
// For access purposes, consider a users to be a friend of themself
$friends[] = $fbu;
if (count($friends))
$grants[FB_GRANT_REALM_FRIEND] = $friends;
$groups = fb_get_groups($fbu);
if (count($groups))
$grants[FB_GRANT_REALM_GROUP] = $groups;
}
return $grants;
}
/**
* Convenience method for displaying facebook api errors.
*/
function fb_report_errors($fb = FB_APP_CURRENT) {
if ($fb == FB_APP_CURRENT) {
$fb = $GLOBALS['fb'];
}
if ($fb) {
if ($fb->api_client->error_code) {
$message = t('Facebook API error %code (see !link).',
array('%code' => $fb->api_client->error_code,
'!link' => l(t('error codes'), "http://wiki.developers.facebook.com/index.php/Error_codes"),
));
watchdog('fb', $message, WATCHDOG_ERROR);
drupal_set_message($message, 'error');
}
}
}
/**
* Exception handler for PHP5 exceptions.
*/
function fb_report_exception($exception) {
$message = t('Facebook API exception %message. !trace',
array('%message' => $exception->getMessage(),
'!trace' => ''.$exception->getTraceAsString().'
',
));
watchdog('fb', $message, WATCHDOG_ERROR);
drupal_set_message($message, 'error');
print $message;
}
?>