$val) { if (strpos($key, 'fb_') === 0) $req[] = $key . '=' . $val; } $url = url($_REQUEST['q'], array('query' => $req, 'absolute' => TRUE)); if (fb_verbose() == 'extreme') watchdog('fb_debug', 'Facebook session key was "%old", now "%new". Destroying session and sending user to %url.', array( '%old' => $_SESSION['fb_frame_params']['session_key'], '%new' => $_REQUEST['fb_sig_session_key'], '%url' => $url, )); session_destroy(); drupal_goto($url); } } } // Purge out-of-date session info if (isset($_SESSION['fb_frame_params']) && $_SESSION['fb_frame_params']['expires'] && $_SESSION['fb_frame_params']['expires'] < time()) { unset($_SESSION['fb_frame_params']); } // Perform sanity check, help users who skip the README. if (!variable_get('fb_settings_check', FALSE) && user_access('access administration pages')) { drupal_set_message(t('!drupal_for_facebook has been enabled, but not properly installed. Please read the !readme.', array('!drupal_for_facebook' => l(t('Drupal for Facebook'), 'http://drupal.org/project/fb'), // This link should work with clean URLs // disabled. '!readme' => 'README.txt')), 'error'); } // Ask other modules for app details. $_fb_app = fb_invoke(FB_OP_CURRENT_APP); // DEPRECATED global $fb_app has been renamed to $_fb_app. $GLOBALS['fb_app'] = $_fb_app; // For compatibility with old third-party modules. if ($_fb_app) { // we are in a callback // For canvas and connect pages, use current user. $_fb = fb_api_init($_fb_app, FB_FBU_CURRENT); // DEPRECATED global $fb has been renamed to $_fb. $GLOBALS['fb'] = $_fb; // For compatibility with old third-party modul if ($_fb) { // Give other modules a chance to initialize, require login, etc... fb_invoke(FB_OP_INITIALIZE, array( 'fb_app' => $_fb_app, 'fb' => $_fb)); // See if the facebook user id is known if ($fbu = $_fb->get_loggedin_user()) { fb_invoke(FB_OP_APP_IS_AUTHORIZED, array( 'fb_app' => $_fb_app, 'fb' => $_fb, 'fbu' => $fbu)); } } else watchdog('fb', "URL indicates a facebook app, but could not initialize Facebook", array(), WATCHDOG_ERROR); } fb_invoke(FB_OP_POST_INIT, array('fb_app' => $_fb_app, 'fb' => $_fb)); } /** * Include the necessary facebook-platform code and initialize the API object. * * @param fbu To log into facebook as a particular user, pass the facebook id. * This is useful during cron jobs, for example, but rarely if ever needed on * a canvas page. If no valid session key is known for the user, this call * will still return a facebook reference. * * If FB_FBU_ANY is passed in, we will log in as the canvas page user if * already logged in. Otherwise we try the infinite session, if configured. * * Future calls into the the facebook api could fail for various reasons. For * one, we may fail to log in as the specified user. This call does not * actually contact facebook to test the connection, it just sets things up so * that when the connection is needed, it might work. Even if the connection * is established, the user may not have sufficient permission to whatever you * are asking facebook to do. * */ function fb_api_init($fb_app, $fbu = FB_FBU_CURRENT) { //dpm(func_get_args(), "fb_api_init"); //$trace = debug_backtrace(); //dpm($trace, "fb_api_init call stack"); static $cache = array(); // This helps with uncaught exceptions. However, it should be configurable // or at least not overwrite previously declared handler. set_exception_handler('fb_handle_exception'); if (!count($cache)) { $filename = variable_get('fb_api_file', 'facebook-platform/php/facebook.php'); if (!include($filename)) { $message = t('Failed to find the Facebook client libraries at %filename. Read the !readme and follow the instructions carefully.', array( '!drupal_for_facebook' => l(t('Drupal for Facebook'), 'http://drupal.org/project/fb'), // This link should work with clean URLs disabled. '!readme' => 'README.txt', '%filename' => $filename, )); drupal_set_message($message, 'error'); watchdog('fb', $message); return NULL; } } // This global comes from facebook's client API. $GLOBAL['facebook_config']['debug'] = variable_get('fb_debug', FALSE); // set TRUE for debug output from FB API if (!isset($cache[$fb_app->apikey])) { $cache[$fb_app->apikey] = array(); } $fbu_orig = $fbu; // Avoid E_NOTICE errors and keep code below clean. if (isset($GLOBALS['_fb'])) { $global_fb = $GLOBALS['_fb']; } else { $global_fb = (object) array('api_key' => NULL); } // Determine the actual facebook user id to use. if ($global_fb->api_key == $fb_app->apikey && ($fbu == FB_FBU_CURRENT || $fbu == FB_FBU_ANY || $fbu == $GLOBALS['_fb']->get_loggedin_user())) { return $GLOBALS['_fb']; } elseif ($global_fb->api_key == $fb_app->apikey && ($fbu == FB_FBU_CURRENT || $fbu == FB_FBU_ANY) && isset($_SESSION['fb_frame_params']) && !$_REQUEST['fb_sig']) { $params = $_SESSION['fb_frame_params']; $fbu = $params['user']; $session = $params['session_key']; } elseif ($global_fb->api_key == $fb_app->apikey && $fbu == FB_FBU_CURRENT) { // No current user to use, probably anonymous canvas page. return $GLOBALS['_fb']; } elseif (is_numeric($fbu)) { // FB user id passed in. If we happen to have valid session info for // them, we can log in as them. $data = fb_invoke(FB_OP_GET_USER_SESSION, array( 'fb_app' => $fb_app, 'fbu' => $fbu), array()); if (count($data) && $data[0] && $data[1]) { $fbu = $data[0]; $session = $data[1]; } } if (!isset($cache[$fb_app->apikey][$fbu])) { try { // We don't have a cached resource for this app/user combo, so we're going to create one. $fb = new Facebook($fb_app->apikey, $fb_app->secret); // Iframes may link or redirect within the iframe, in which case facebook // will not provide all its normal variables. To prepare for such a case, // we cache the facebook parameters in the session. // We update the cache whenever possible, to keep it current. if ($fb->in_frame() && $fb->fb_params && $fb->api_client->session_key) { $_SESSION['fb_frame_params'] = $fb->fb_params; // hacky to use fb's internal data structure } // If we learned the session, above, use it if ($fbu && isset($session)) { $fb->set_user($fbu, $session); } elseif ($fbu && $fbu == $fb->get_loggedin_user()) { // Canvas page or Connect page, current user is logged in already. // Nothing to do here. } elseif ($fbu == FB_FBU_NO_SESSION) { $fb->set_user(NULL, NULL); } // Cache the result, in case we're called again. $cache[$fb_app->apikey][$fbu] = $fb; // Note that facebook api has not actually logged into facebook yet. // We won't really know if our session is valid until later. // get_loggedin_user does not really test it. if ($fbu_orig != FB_FBU_NO_SESSION && $fbu_orig != FB_FBU_CURRENT && !$fb->get_loggedin_user()) { // An FBU other than CURRENT was specified, but we failed to log in. watchdog('fb', 'Failed to log into facebook app %app as user %user', array('%app' => $fb_app->title, '%user' => $fbu_orig), WATCHDOG_ERROR); } } catch (Exception $e) { fb_log_exception($e, t('Failed to construct Facebook client API.')); } } $fb = $cache[$fb_app->apikey][$fbu]; return $fb; } /** * Wrapper function for fb_api_init. This helps for functions that should * work whether or not we are on a canvas page. For canvas pages, the active * fb object is used. For non-canvas pages, it will initialize the API using * an infinite session, if configured. * * @param $fb_app Note this is ignored on canvas pages. * * This is for internal use. Third party modules use fb_api_init(). */ function _fb_api_init($fb_app = NULL) { $fb = $GLOBALS['_fb']; // Default to active app on canvas pages if (!$fb && $fb_app) // Otherwise, log into facebook api. $fb = fb_api_init($fb_app, FB_FBU_ANY); if (!$fb) { watchdog('fb', '%function unable to initialize Facebook API.', array('%function' => '_fb_api_init()'), WATCHDOG_ERROR); return; } else return $fb; } /** * Sometimes calls to fb_api_init succeed, but calls to the client api * will fail because cookies are obsolete or what have you. This * function makes a call to facebook to test the session. Expensive, * so use only when necessary. */ function fb_api_check_session($fb) { // TODO: caching $success = FALSE; try { $is_user = $fb->api_client->users_isAppUser(); // Does not matter what is returned, as long as exception is not thrown. $success = TRUE; } catch (Exception $e) { $success = FALSE; } return $success; } /** * Returns the facebook user id currently visiting a canvas page, or if set_user has been called. * Unlike fb_get_fbu(), works only on canvas pages or when infinite session has been initialized. */ function fb_facebook_user($fb = NULL) { if (!isset($fb)) $fb = $GLOBALS['_fb']; if (!$fb) return; $fbu = $fb->get_loggedin_user(); if (isset($fb->api_client->error_code)) { if (fb_verbose()) { watchdog('fb', 'Failed to get Facebook user id. detail: !detail', array('!detail' => print_r($_REQUEST, 1)), WATCHDOG_ERROR); } } return $fbu; } /** * Determine whether current page is FBML canvas page. */ function fb_is_fbml_canvas() { if (function_exists('fb_canvas_is_fbml')) // More complex logic if fb_canvas.module enabled. return fb_canvas_is_fbml(); else { if (isset($GLOBALS['_fb'])) { return $GLOBALS['_fb']->in_fb_canvas(); } } } /** * Determine whether current page is iframe canvas page. */ function fb_is_iframe_canvas() { if (function_exists('fb_canvas_is_iframe')) // More complex logic if fb_canvas.module enabled. return fb_canvas_is_iframe(); else { if (isset($GLOBALS['_fb'])) { return $GLOBALS['_fb']->in_frame(); } } } function fb_is_connect() { // fb_settings.inc sets this global. if (isset($GLOBALS['_fb_connect_apikey'])) { return $GLOBALS['_fb_connect_apikey']; } elseif (function_exists('fb_connect_get_app')) { $fb_app = fb_connect_get_app(); if (isset($fb_app)) return $fb_app->apikey; } } /** * Helper tells other modules when to load admin hooks. */ function fb_is_fb_admin_page() { if (arg(0) == 'admin' && (arg(1) == 'fb' || arg(2) == 'fb')) { // Keep consistant titles across tabs served by multiple modules. if ($label = arg(FB_PATH_ADMIN_APPS_ARGS)) drupal_set_title($label); else drupal_set_title(t('Drupal for Facebook')); return TRUE; } } /** * Determine whether we are rendering a profile tab. */ function fb_is_profile_tab() { if (isset($_REQUEST['fb_sig_in_profile_tab'])) return $_REQUEST['fb_sig_in_profile_tab']; } function fb_get_profile_id() { if (isset($_REQUEST['fb_sig_profile_id'])) return $_REQUEST['fb_sig_profile_id']; } /** * Facebook provides a method, users_isAppUser(), which is buggy and * unreliable. So we need to implement our own. */ function fb_is_app_user($fb) { if ($fb->api_client->added || $fb->api_client->is_user) return TRUE; else return $fb->api_client->users_isAppUser; } /** * Given a local user id, find the facebook id. */ function fb_get_fbu($uid, $fb_app = NULL) { // default to current app (only set if we're in a FB callback) if (!$fb_app) $fb_app = $GLOBALS['_fb_app']; // Accept either a user object or uid passed in. if (is_object($uid) && ($uid->uid) && isset($uid->fbu) && $uid->fbu) return $uid->fbu; elseif (is_object($uid)) $uid = $uid->uid; if ($uid) { // User management is handled by another module. Use our hook to ask for mapping. $fbu = fb_invoke(FB_OP_GET_FBU, array('fb_app' => $fb_app, 'uid' => $uid, 'fb' => $GLOBALS['_fb'])); } return $fbu; } /** * Convenience function to learn the fbu associated with a user, node or comment. * Used in theming (X)FBML tags. */ function fb_get_object_fbu($object) { static $cache; if (!isset($cache)) $cache = array(); if (isset($object->uid) && isset($cache[$object->uid])) { $fbu = $cache[$object->uid]; return $fbu; } elseif (isset($object->fbu)) { // Explicitly set. $fbu = $object->fbu; } elseif ($pos = strpos($object->name, '@facebook')) { // Naming convention. $fbu = substr($object->name, 0, $pos); } elseif ($object->uid > 0) { // Experimental. This can be expensive on pages with many comments or nodes! //$fbu = fb_get_fbu($object->uid); } if (isset($fbu) && is_numeric($fbu)) { if (isset($object->uid) && ($object->uid > 0)) { $cache[$object->uid] = $fbu; } return $fbu; } } /** * Convenience method to get an apps callback URL. * * TODO: This code will probably not handle every case and may need some work. */ function fb_get_callback_url($fb_app) { $url = url('', array('absolute' => TRUE)) . FB_SETTINGS_APP_LABEL . '/'. $fb_app->label . '/'; return $url; } /** * Convenience method to get app info based on apikey or nid. */ function fb_get_app($search_data) { // $search_data can be an apikey, or an array of other search params. if (!is_array($search_data)) $search_data = array('apikey' => $search_data); $fb_app = fb_invoke(FB_OP_GET_APP, $search_data); return $fb_app; } /** * Convenience method for other modules to attach data to the fb_app * object. * * It is assumed the fb_app implementation will fill in the data * field. We really should clean up the separation between modules, * or merge fb_app.module into this one. */ function fb_get_app_data(&$fb_app) { if (!isset($fb_app->fb_app_data)) { $fb_app->fb_app_data = isset($fb_app->data) ? unserialize($fb_app->data) : array(); } return $fb_app->fb_app_data; } /** * Will return a human-readable name if the fb_app module supports it, or * fb_admin_get_app_properties($fb_app) has been called. However we don't * take the relatively expensive step of calling that ourselves. */ function fb_get_app_title($fb_app) { if (isset($fb_app->title)) return $fb_app->title; elseif (isset($fb_app->application_name)) { return $fb_app->application_name; } else { return $fb_app->label; } } /** * 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"; // FQL, no {curly_brackets}! $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; } } } //// Menu structure. /** * Implementation of hook_menu(). */ function fb_menu() { $items = array(); // Admin pages overview. $items[FB_PATH_ADMIN] = array( 'title' => 'Facebook Applications', 'description' => 'Facebook Applications', 'page callback' => 'fb_admin_page', 'access arguments' => array(FB_PERM_ADMINISTER), 'file' => 'fb.admin.inc', 'type' => MENU_NORMAL_ITEM, ); $items[FB_PATH_ADMIN . '/list'] = array( 'title' => 'List', 'weight' => -2, 'type' => MENU_DEFAULT_LOCAL_TASK, ); // Admin pages for each app. $items[FB_PATH_ADMIN_APPS . '/%fb'] = array( 'title' => 'Application Detail', 'description' => 'Facebook Applications', 'page callback' => 'fb_admin_app_page', 'page arguments' => array(FB_PATH_ADMIN_APPS_ARGS), 'access arguments' => array(FB_PERM_ADMINISTER), 'file' => 'fb.admin.inc', 'type' => MENU_CALLBACK, ); $items[FB_PATH_ADMIN_APPS .'/%fb/fb'] = array( 'title' => 'View', 'weight' => -2, '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 a %wildcard_load(). http://drupal.org/node/224170 */ function fb_load($id) { $query = array(FB_SETTINGS_APP_LABEL => $id); if (fb_is_fb_admin_page()) { // Show disabled apps to admins. $query['status'] = 0; // status >= 0 } $fb_app = fb_get_app($query); return $fb_app; } /** * Implementation of hook_perm(). */ function fb_perm() { return array(FB_PERM_ADMINISTER); } /** * 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); if (fb_verbose() == 'extreme') { watchdog('fb', "Returning cached form page $cid"); // debug } $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, $hook = FB_HOOK) { foreach (module_implements($hook) as $name) { $function = $name . '_' . $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_LABEL, 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" . 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) { // See if this is a request for us. if (strpos($path, FB_SETTINGS_APP_LABEL . '/') === 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_label = fb_settings(FB_SETTINGS_APP_LABEL)) { 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 (is_array($info) && is_array($info[0])) { if ($info[0]['name']) { $name = $info[0]['name']; } } } }