');
foreach ($apps as $app) {
if ($key == 'apikey') {
$options[$app->apikey] = $app->title;
}
else {
$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(FB_OP_GET_ALL_APPS, NULL, array());
return $apps;
}
/**
* A convenience method for returning a list of facebook friends.
*
* This should work efficiently in canvas pages for finding friends of
* the current user. In other cases it tries to work, but will be an
* expensive operation and only succeed when the user is logged in via
* Connect, or has created an infinite session.
*
* @return: an array of facebook ids
*/
function fb_get_friends($fbu, $fb_app = NULL) {
static $cache = array();
if (!$fb_app)
$fb_app = $GLOBALS['fb_app'];
// Facebook only allows us to query the current user's friends, so let's try
// to log in as that user. It will only actually work if they are the
// current user of a canvas page, or they've signed up for an infinite
// session.
$fb = fb_api_init($fb_app, $fbu);
if (!$fb || !$fbu)
return;
if (!isset($cache[$fbu])) {
if ($fb === $GLOBALS['fb'] &&
$fbu == fb_facebook_user($fb))
$items = $fb->api_client->friends_get();
// friends_get does not work in cron call, so we double check.
if (!$items || !count($items)) {
$logged_in = fb_facebook_user($fb);
$query = "SELECT uid2 FROM friend WHERE uid1=$fbu";
$result = $fb->api_client->fql_query($query);
fb_report_errors($fb);
$items = array();
if (is_array($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, $fb_app = NULL) {
$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, $fb_app = NULL) {
static $cache = array();
$fb = _fb_api_init($fb_app);
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', 'Failed to load user from facebook fbu=%fbu',
array('%fbu' => $fbu), WATCHDOG_ERROR);
$account->fbu = $fbu;
return $account;
}
}
function fb_form_alter(&$form, &$form_state, $form_id) {
// 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() {
$items = array();
// Admin pages
$items['admin/fb'] = array(
'title' => 'Facebook Apps',
'description' => t('Facebook Applications'),
'page callback' => 'fb_admin_page',
'access arguments' => array(FB_PERM_ADMINISTER),
'file' => 'fb.admin.inc',
'type' => MENU_NORMAL_ITEM,
);
$items['admin/fb/apps'] = array(
'title' => 'Apps',
'weight' => -1,
'type' => MENU_DEFAULT_LOCAL_TASK,
);
// When forms are submitted directly to us, we cache the results,
// and show them later via this callback
$items['fb/form_cache'] = array(
'page callback' => '_fb_form_cache_cb',
'type' => MENU_CALLBACK,
'access callback' => TRUE
);
return $items;
}
/**
* Implementation of hook_perm().
*/
function fb_perm() {
return array(FB_PERM_ADMINISTER, FB_PERM_CREATE, FB_PERM_EDIT_OWN);
}
/**
* When exiting we need to do some special stuff for forms
*/
function fb_exit($destination = NULL) {
global $fb_app, $fb;
if ($fb_app && $fb) {
fb_invoke(FB_OP_EXIT, array('fb_app' => $fb_app,
'fb' => $GLOBALS['fb']),
$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_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;
}
/**
* Invoke hook_fb.
*/
function fb_invoke($op, $data = NULL, $return = NULL) {
foreach (module_implements(FB_HOOK) as $name) {
$function = $name . '_' . FB_HOOK;
try {
$function($op, $data, $return);
}
catch (Exception $e) {
fb_log_exception($e, t('Exception calling %function(%op)',
array('%function' => $function,
'%op' => $op)));
}
}
return $return;
}
/**
* This method will clean up URLs. When serving canvas pages, extra
* information is included in URLs (see fb_settings.inc). This will remove
* the extra information.
*/
function fb_scrub_urls($content) {
foreach (array(FB_SETTINGS_APP_NID, FB_SETTINGS_PAGE_TYPE) as $key) {
$patterns[] = "|$key/[^/]*/|";
$replacements[] = "";
}
$content = preg_replace($patterns, $replacements, $content);
return $content;
}
/**
* 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.
*
* DEPRECATED. Not sure where, if anywhere, this belongs.
*/
function fb_node_grantsXXX($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, $message = NULL) {
if ($fb == FB_APP_CURRENT) {
$fb = $GLOBALS['fb'];
}
if ($fb) {
if (isset($fb->api_client->error_code)) {
$message = t('!message 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"),
'!message' => $message,
));
watchdog('fb', $message, array(), WATCHDOG_ERROR);
if (user_access(FB_PERM_ADMINISTER)) {
drupal_set_message($message, 'error');
}
}
}
}
function fb_log_exception($e, $text = '', $fb = NULL) {
if ($text)
$message = $text .': '. $e->getMessage();
else
$message = $e->getMessage();
$message .= ' ' . $e->getCode();
if ($fb) {
$message .= '. (' . t('logged into facebook as %fbu', array('%fbu' => $fb->get_loggedin_user())) . ')';
}
if (fb_verbose()) {
$message .= '' . $e . '
';
}
watchdog('fb', $message, array(), WATCHDOG_ERROR);
if (user_access(FB_PERM_ADMINISTER)) {
drupal_set_message($message, 'error');
}
}
/**
* Exception handler for PHP5 exceptions.
*/
function fb_handle_exception($exception) {
$message = t('Facebook API exception %message. !trace',
array('%message' => $exception->getMessage(),
'!trace' => ''.$exception->getTraceAsString().'
',
));
watchdog('fb', $message, array(), WATCHDOG_ERROR);
//drupal_set_message($message, 'error');
print $message;
print "\$_REQUEST:\n";
print_r($_REQUEST);
print "\n\nREQUEST_URI:\n" . $_SERVER['REQUEST_URI'];
print "
";
}
/**
* Helper function for facebook's users_getInfo API.
*
* This function makes calls to users_getInfo more efficient, by caching
* results in the session, so calls do not always require hitting Facebook's
* servers.
*
* @param $oids
* Array of facebook object IDs. In this case they should each be a user id.
*/
function fb_users_getInfo($oids, $fb = NULL, $refresh_cache = FALSE) {
if (!$fb) {
$fb = $GLOBALS['fb'];
}
$infos = array();
if (!is_array($oids))
$oids = array();
if ($fb) {
// First try cache
if (!$refresh_cache)
foreach ($oids as $oid) {
if ($info = $_SESSION['fb'][$fb->api_key]['userinfo'][$oid])
$infos[] = $info;
}
if (count($infos) != count($oids)) {
// Session cache did not include all users, update the cache.
$infos = $fb->api_client->users_getInfo($oids,
array('about_me',
'affiliations',
'name',
'is_app_user',
'pic',
'pic_big',
'pic_square',
'profile_update_time',
'proxied_email',
'status',
'email_hashes',
'email',
));
// Update cache with recent results.
if (is_array($infos)) {
foreach($infos as $info) {
$_SESSION['fb'][$fb->api_key]['userinfo'][$info['uid']] = $info;
}
}
}
return $infos;
}
}
/**
* Helper function for FBJS files.
*
* Useful for adding Facebook Javascript, which will be incorporated into
* canvas pages or profile boxes. When included this way, javascript must be
* embedded inline, rather than refer to an external URL. So this function
* will actually read a local file and include the contents inline.
*/
function fb_add_js($filename, $type) {
static $cache;
if (!$cache) {
$cache = array();
// Add the most basic file we need.
$base_file = drupal_get_path('module', 'fb') . '/fb_fbml.js';
$base_file .= "?v=".filemtime($base_file);
drupal_add_js($base_file, 'module', 'fbml');
// Add some settings that FBJS code will often need.
$baseUrl = url('', array('absolute' => TRUE));
drupal_add_js(array('fbjs' => array('baseUrlFb' => $baseUrl,
'baseUrl' => fb_scrub_urls($baseUrl),
),
),
'setting', 'fbml');
}
if (!$cache[$filename]) {
if (file_exists($filename)) {
// Refresh facebook's cache when file changes
$filename .= "?v=".filemtime($filename);
}
// 'post_settings' is a hack to make our code come after settings. This is
// ugly, but we're doing it because there is no "onready" in FBJS.
drupal_add_js($filename, 'post_settings', 'fbml');
$cache[$filename] = TRUE;
}
}
/**
* For debugging, add $conf['fb_verbose'] = TRUE; to settings.php.
*/
function fb_verbose() {
return variable_get('fb_verbose', NULL);
}
/**
* Define custom_url_rewrite_inbound() if not defined already.
*/
if (!function_exists('custom_url_rewrite_inbound')) {
function custom_url_rewrite_inbound(&$result, $path, $path_language) {
fb_url_inbound_alter($result, $path, $path_language);
}
}
/**
* Define custom_url_rewrite_outbound() if the url_alter.module is not enabled.
*/
if (!function_exists('custom_url_rewrite_outbound')) {
function custom_url_rewrite_outbound(&$path, &$options, $original_path) {
fb_url_outbound_alter($path, $options, $original_path);
}
}
/**
* Implementation of hook_url_outbound_alter().
*/
function fb_url_outbound_alter(&$path, &$options, $original_path) {
//dpm(func_get_args(), 'fb_settings_url_rewrite_outbound');
$pre = '';
// Prefix each known value to the URL
foreach (_fb_settings_url_rewrite_prefixes() as $prefix) {
if ($value = fb_settings($prefix))
$pre .= $prefix . '/'. $value . '/';
}
$path = $pre . $path;
return $path;
}
/**
* Implementation of hook_url_inbound_alter().
*
* Rewrite URLs for facebook canvas pages, and connect callbacks.
*
*/
function fb_url_inbound_alter(&$result, $path, $path_language){
//$origpath = $path;
//watchdog('fb_settings', "fb_settings_url_rewrite_inbound($result, $path, $path_language)", array(), WATCHDOG_DEBUG);
// See if this is a request for us.
if (strpos($path, FB_SETTINGS_APP_NID . '/') === 0) {
// Too soon for arg() function.
$args = explode('/', $path);
while (count($args) && in_array($args[0], _fb_settings_url_rewrite_prefixes())) {
$key = array_shift($args);
$value = array_shift($args);
$app_nid = fb_settings($key, $value); // Store for use later.
}
if ($app_nid = fb_settings(FB_SETTINGS_APP_NID)) {
if (count($args)) {
$path = implode('/', $args); // remaining args
$alias = drupal_lookup_path('source', $path, $path_language); //can't use drupal_get_normal_path, it calls custom_url_rewrite_inbound
if ($alias)
$path = $alias;
}
else {
// frontpage
$path = variable_get('site_frontpage', 'node');
$alias = drupal_lookup_path('source', $path, $path_language);
if ($alias)
$path = $alias;
$_REQUEST['destination'] = $path; //required workaround for compatibility with Global Redirect module, best practice?
}
}
}
else { //resolve aliases for non-fb-callbacks
$alias = drupal_lookup_path('source', $path, $path_language);
if ($alias)
$path = $alias;
}
$result = $path;
}
/**
* This function will be replaced, hopefully, by format_username in D7.
*
* See http://drupal.org/node/192056
*/
function fb_format_username($account) {
$name = !empty($account->name) ? $account->name : variable_get('anonymous', t('Anonymous'));
drupal_alter('username', $name, $account);
return $name;
}
/**
* hook_username_alter().
*
* Return a user's facebook name, instead of local username.
*/
function fb_username_alter(&$name, $account) {
//dpm(func_get_args(), "fb_username_alter($name)");
if (isset($account->fbu) && ($name == $account->fbu . '@facebook')) {
$info = fb_users_getInfo(array($account->fbu));
if ($info[0]['name']) {
$name = $info[0]['name'];
}
}
}
?>