'Canvas Pages',
'description' => 'Configure Canvas Pages',
'page callback' => 'drupal_get_form',
'page arguments' => array('fb_canvas_admin_settings'),
'access arguments' => array(FB_PERM_ADMINISTER),
'file' => 'fb_canvas.admin.inc',
'type' => MENU_LOCAL_TASK,
);
return $items;
}
/**
* Implementation of hook_fb().
*/
function fb_canvas_fb($op, $data, &$return) {
static $original_uid;
global $user;
$fb = isset($data['fb']) ? $data['fb'] : NULL;
$fb_app = isset($data['fb_app']) ? $data['fb_app'] : NULL;
if ($op == FB_OP_CURRENT_APP) {
if (function_exists('fb_settings')) {
if ((fb_settings(FB_SETTINGS_TYPE) == FB_SETTINGS_TYPE_CANVAS) &&
($apikey = fb_settings(FB_SETTINGS_APIKEY))) {
// This is the proper way to discover the app on canvas pages.
$fb_app = fb_get_app(array('apikey' => $apikey));
// If were on an iframe excursion, the fb_sig will be in session.
if (!isset($_REQUEST['fb_sig']) &&
isset($_SESSION['fb_canvas_fb_sig'])) {
foreach ($_SESSION['fb_canvas_fb_params'] as $k => $value) {
$key = 'fb_sig_' . $k;
if (!isset($_REQUEST[$key])) {
// We use $_REQUEST, facebook uses $_GET.
$_REQUEST[$key] = $value;
$_GET[$key] = $value;
}
}
$_REQUEST['fb_sig'] = $_SESSION['fb_canvas_fb_sig'];
$_GET['fb_sig'] = $_SESSION['fb_canvas_fb_sig'];
}
}
elseif ($id = fb_settings(FB_SETTINGS_CB)) {
// This is the old way dependent on url rewriting.
$fb_app = fb_get_app(array('id' => $id));
}
}
else {
// Fallback in case fb_settings not used.
if (isset($_REQUEST[FB_APP_REQ_API_KEY]) &&
($apikey = $_REQUEST[FB_APP_REQ_API_KEY])) {
// If facebook has passed the app key, let's use that.
$fb_app = fb_get_app(array('apikey' => $apikey));
}
}
if ($fb_app)
$return = $fb_app;
}
elseif ($op == FB_OP_INITIALIZE) {
// Get our configuration settings.
$fb_app_data = fb_get_app_data($fb_app);
$fb_canvas_data = $fb_app_data['fb_canvas'];
$is_canvas = FALSE;
// Set an app-specific theme.
global $custom_theme; // Set by this function.
if (fb_canvas_is_fbml()) {
$custom_theme = $fb_canvas_data['theme_fbml'];
$is_canvas = TRUE;
$use_ob = variable_get(FB_CANVAS_VAR_PROCESS_FBML, TRUE);
}
elseif (fb_canvas_is_iframe()) {
$custom_theme = $fb_canvas_data['theme_iframe'];
$is_canvas = TRUE;
$use_ob = variable_get(FB_CANVAS_VAR_PROCESS_IFRAME, TRUE);
}
if ($is_canvas) {
// We are serving a canvas page.
$conf['admin_theme'] = $custom_theme;
if ($fb_canvas_data['require_login'] == FB_CANVAS_OPTION_REQUIRE_LOGIN) {
// The application is configured to require login on all canvas pages.
// However, there are exceptions.
if (fb_is_profile_tab()) {
// Redirects are not allowed for the profile tab.
}
else {
// There may be other exceptions, for example some ajax callbacks. Potential todo item.
$fb->require_login();
}
}
// Remember the user id. If fb_user.module changes it, we'll need to refresh the page. See FB_OP_POST_INIT.
$original_uid = $user->uid;
// Hack to init the theme before _drupal_maintenance_theme initializes the wrong one.
if (variable_get('site_offline', FALSE)) {
$dummy = theme('dummy');
}
}
// Use buffer for form posts.
if (!$use_ob && fb_canvas_handling_form()) {
$use_ob = variable_get(FB_CANVAS_VAR_PROCESS_FBML_FORM, TRUE);
}
// Store entire page in output buffer. Will post-process on exit.
if ($use_ob) {
ob_start();
$GLOBALS['fb_canvas_post_process'] = TRUE;
}
if ($is_canvas &&
$_GET['q'] == drupal_get_normal_path(
variable_get('site_frontpage', 'node'))) {
if ($fb->get_loggedin_user()) {
if ($fb->api_client->users_isAppUser())
$front = $fb_canvas_data['front_added'];
else
$front = $fb_canvas_data['front_loggedin'];
}
else
$front = $fb_canvas_data['front_anonymous'];
if ($front)
menu_set_active_item(drupal_get_normal_path($front));
}
}
elseif ($op == FB_OP_POST_INIT) {
//dpm($_REQUEST, "request post init");
if (isset($original_uid) &&
$original_uid != $user->uid) {
// The user has changed, presumably fb_user.module recognized the facebookuser. We need to refresh canvas pages.
if (!(arg(0) == 'fb_app' && arg(1) == 'event')) {
// In order to ensure that drupal handles
// permissions properly, the user must make the request all over
// again. Skip this for the profile tab, as facebook does not allow
// redirects (or persistent session) there.
if ((fb_canvas_is_fbml() || fb_canvas_is_iframe()) &&
!fb_is_profile_tab()) {
fb_canvas_goto(fb_scrub_urls($_REQUEST['q']));
}
}
}
// The ?destination=... url param means something to drupal but something
// else to facebook. If ?fb_canvas_destination=... is set, we honor that.
if (isset($_REQUEST['fb_canvas_destination'])) {
$_REQUEST['destination'] = $_REQUEST['fb_canvas_destination'];
}
// Give FBML themes a chance to render tabs.
if (fb_canvas_is_fbml()) {
_fb_canvas_menu_hack();
}
// Include our admin hooks.
if (fb_is_fb_admin_page()) {
require drupal_get_path('module', 'fb_canvas') . '/fb_canvas.admin.inc';
}
}
elseif ($op == FB_OP_EXIT) {
/* We do some unpleasant stuff in this hook... on FBML canvas
pages we might use $fb->redirect(), in which case other
modules' hook_exit() might not be called.
In other cases we call drupal_goto(), in which case other
modules' hook_exit() might be called twice. I hate to do this
but so far have not figured another way. And so far no
problems... if problems arise, please post to issue queue.
*/
$destination = $return;
if ($GLOBALS['fb_canvas_post_process']) {
$output = ob_get_contents();
ob_end_clean();
if (fb_canvas_is_fbml()) {
$output = fb_canvas_process($output, array('force_absolute_canvas' => TRUE));
}
elseif (fb_canvas_is_iframe()) {
$output = fb_canvas_process($output, array('add_target' => TRUE));
}
}
if (fb_canvas_handling_form() &&
fb_canvas_handling_form() !== 'avoid_loop' &&
$output) {
// Avoid infinite loop if we get called from drupal_goto.
fb_canvas_handling_form('avoid_loop');
// Special handling for forms submitted to Drupal from FBML canvas pages.
// Cache the results to show the user later.
$token = uniqid('fb_');
$cid = session_id() . "_$token";
cache_set($cid, $output, 'cache_page', time() + (60 * 5), drupal_get_headers()); // (60 * 5) == 5 minutes
$dest = 'http://apps.facebook.com/' . $fb_app->canvas . "/fb/form_cache/$cid";
// $fb->redirect($dest); // Does not work!
// Preserve some URL parameters
$query = array();
foreach (array('fb_force_mode') as $key) {
if ($_REQUEST[$key])
$query[] = $key . '=' . $_REQUEST[$key];
}
// drupal_goto honors $_REQUEST['destination'], but we only want
// that when no errors occurred.
if (form_get_errors()) {
unset($_REQUEST['destination']);
if ($_REQUEST['edit'])
unset($_REQUEST['edit']['destination']);
}
if (fb_verbose() == 'extreme') {
watchdog('fb', "Storing cached form page $cid, then redirecting to $dest, query is " . implode('&', $query));
}
drupal_goto($dest, implode('&', $query), NULL, 303); // appears to work
}
if ((fb_canvas_is_fbml() || fb_canvas_is_iframe()) &&
(!isset($GLOBALS['_fb_canvas_goto']))) {
if ($destination) {
// Fully qualified URLs need to be modified to point to facebook app.
// URLs are fully qualified when a form submit handler returns a path,
// or any call to drupal_goto.
$app_destination = fb_canvas_fix_url($destination, $fb_app);
// If here, drupal_goto has been called, but it may not work within a
// canvas page, so we'll use Facebook's method.
// Unfortunately, other modules' hook_exit() may not be called.
if (fb_verbose()) {
watchdog('fb_debug', "FB_OP_EXIT on canvas page redirecting to $app_destination (original destination was $destination).");
$fb->redirect($app_destination);
}
}
}
if (isset($output)) {
print($output);
}
}
}
/**
* Helper returns configuration for this module, on a per-app basis.
*/
function _fb_canvas_get_config($fb_app) {
$fb_app_data = fb_get_app_data($fb_app);
$fb_canvas_data = $fb_app_data['fb_canvas'] ? $fb_app_data['fb_canvas'] : array();
// Merge in defaults
$fb_canvas_data += array(
'require_login' => FB_CANVAS_OPTION_ALLOW_ANON,
'theme_fbml' => 'fb_fbml',
'theme_iframe' => 'fb_fbml',
);
return $fb_canvas_data;
}
/**
* Implementation of hook_form_alter.
*/
function fb_canvas_form_alter(&$form, &$form_state, $form_id) {
// Add our settings to the fb_app edit form.
if (isset($form['fb_app_data']) && is_array($form['fb_app_data'])) {
$fb_app = $form['#fb_app'];
$fb_canvas_data = _fb_canvas_get_config($fb_app);
$form['fb_app_data']['fb_canvas'] = array(
'#type' => 'fieldset',
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#title' => t('Facebook canvas pages'),
'#description' => t('Settings which apply to canvas pages.',
array('!url' => 'http://developers.facebook.com/get_started.php?tab=anatomy#canvas')),
);
$form['fb_app_data']['fb_canvas']['require_login'] = array(
'#type' => 'radios',
'#title' => t('Require authorization'),
'#description' => t('Require authorization if you want Drupal for Facebook to call require_login() on every canvas page.'),
'#options' => array(
FB_CANVAS_OPTION_ALLOW_ANON => t('Allow anonymous visitors'),
FB_CANVAS_OPTION_REQUIRE_LOGIN => t('Require all users to authorize the application'),
),
'#default_value' => $fb_canvas_data['require_login'],
'#required' => TRUE,
);
$form['fb_app_data']['fb_canvas']['front_anonymous'] =
array('#type' => 'textfield',
'#title' => t('Front page when user is not logged in to facebook'),
'#description' => t('Leave blank to use the site-wide front page. See Public Canvas Pages.',
array('!link' => 'http://wiki.developers.facebook.com/index.php/Public_Canvas_Pages')),
'#default_value' => $fb_canvas_data['front_anonymous'],
);
$form['fb_app_data']['fb_canvas']['front_loggedin'] =
array('#type' => 'textfield',
'#title' => t('Front page when user is logged in to facebook, but is not a user of the app'),
'#description' => t('Leave blank to use the site-wide front page.'),
'#default_value' => $fb_canvas_data['front_loggedin'],
);
$form['fb_app_data']['fb_canvas']['front_added'] =
array('#type' => 'textfield',
'#title' => t('Front page for authorized users of this application'),
'#description' => t('Leave blank to use the site-wide front page.'),
'#default_value' => $fb_canvas_data['front_added'],
);
// Override themes
$themes = system_theme_data();
ksort($themes);
$theme_options[0] = t('System default');
foreach ($themes as $theme) {
$theme_options[$theme->name] = $theme->name;
}
$form['fb_app_data']['fb_canvas']['theme_fbml'] = array(
'#type' => 'select',
'#title' => t('Theme for FBML pages'),
'#description' => t('Choose only a theme that is FBML-aware.'),
'#options' => $theme_options,
'#required' => TRUE,
'#default_value' => $fb_canvas_data['theme_fbml'],
);
$form['fb_app_data']['fb_canvas']['theme_iframe'] = array(
'#type' => 'select',
'#title' => t('Theme for iframe pages'),
'#description' => t('Choose only a facebook-aware theme'),
'#options' => $theme_options,
'#required' => TRUE,
'#default_value' => $fb_canvas_data['theme_iframe'],
);
}
// We will send all form submission directly to us, not via
// apps.facebook.com/whatever.
if (fb_canvas_is_fbml()) {
//dpm($form, "fb_canvas_form_alter($form_id)"); // debug
// We're in a facebook callback
if (!isset($form['fb_canvas_form_handler'])) {
// Use the form data structure to keep track of whether data is
// posted directly to us, via absolute URL, or instead via
// relative URL on apps.facebook.com/...
$form['fb_canvas_form_handler'] = array(
'#action_fb' => $form['#action'],
'#action_local' => _fb_canvas_make_form_action_local($form['#action']),
);
// This helper function allows third-party modules to control
// where the post goes. By default use local server.
fb_canvas_form_action_via_facebook($form, FALSE);
}
// Drupal includes wacky markup for javascript junk in node forms. It
// makes things look terrible in FBML. It only works when javascript is
// enabled and it should have been implemented to degrade gracefully, but
// it wasn't.
if (isset($form['body_field'])) {
unset($form['body_field']['teaser_js']);
unset($form['body_field']['teaser_include']);
}
}
elseif (fb_canvas_is_iframe()) {
// Include the fb_sig so that when post is received, we know we are still in a canvas.
foreach ($_REQUEST as $key => $value) {
if (strpos($key, 'fb_sig') === 0) {
$form['fb_canvas_iframe'][$key] = array(
'#type' => 'hidden',
'#value' => $value,
);
}
}
}
}
/**
* Call this from your form_alter hook to prevent changes to the
* form's default action.
*/
function fb_canvas_form_action_via_facebook(&$form, $use_facebook = TRUE) {
if (isset($form['fb_canvas_form_handler'])) {
if ($use_facebook) {
$form['#action'] = $form['fb_canvas_form_handler']['#action_fb'];
$form['fb_canvas_form_handler']['_fb_handling_form'] = array(
'#value' => FALSE,
'#type' => 'hidden');
}
else {
$form['#action'] = $form['fb_canvas_form_handler']['#action_local'];
$form['fb_canvas_form_handler']['_fb_handling_form'] = array(
'#value' => TRUE,
'#type' => 'hidden');
}
}
}
/**
* Implementation of hook_footer().
*
* Invoke FB_OP_CANVAS_FBJS_INIT, allowing other modules to insert
* FBJS to the current page.
*/
function fb_canvas_footer($main = 0) {
if (fb_canvas_is_fbml()) {
// Add FBJS only to FBML pages.
global $_fb, $_fb_app;
$data = array('fb' => $_fb, 'fb_app' => $_fb_app);
$extra = fb_invoke(FB_OP_CANVAS_FBJS_INIT, $data, array());
if (count($extra)) {
$extra_js = implode("\n", $extra);
fb_add_js('', ''); // prime javascript
drupal_add_js($extra_js, 'inline', 'fbml');
}
}
}
function fb_canvas_is_fbml() {
global $_fb, $_fb_app;
if ($_fb && $_fb_app) {
// Facebook events are not canvas pages
if (arg(0) == 'fb_app' && arg(1) == 'event')
return FALSE;
else
return ($_fb->in_fb_canvas() || fb_canvas_handling_form());
}
}
function fb_canvas_is_iframe() {
global $_fb, $_fb_app;
if ($_fb && $_fb_app) {
return ($_fb->in_frame() && !fb_canvas_is_fbml());
}
}
function fb_canvas_handling_form($value = NULL) {
global $_fb;
// Test whether a form has been submitted via facebook canvas page.
if ($_fb && isset($_REQUEST['_fb_handling_form'])) {
$result = $_REQUEST['_fb_handling_form'];
}
if (isset($value)) {
$_REQUEST['_fb_handling_form'] = $value;
}
return $result;
}
/**
* This is intended to help sites which have some FBML and some iframe pages.
* Makes the current FBML canvas page an iframe. And attempts to preserve
* session while visiting multiple iframe pages.
*
* Set $conf['fb_session_cookieless_iframe'] = TRUE for best results (but
* perhaps less session security).
*/
function fb_canvas_iframe_excursion() {
if (fb_canvas_is_fbml()) {
$query = $_GET;
unset($query['q']);
$path = $_GET['q'];
$query['XDEBUG_SESSION_START']=1;
if (function_exists('fb_settings')) {
fb_settings(FB_SETTINGS_CB, $GLOBALS['_fb_app']->label);
fb_settings(FB_SETTINGS_CB_SESSION, fb_settings(FB_SETTINGS_SESSION_KEY));
}
// Make the FBML page a canvas page.
print ('');
unset($_SESSION['fb_canvas_fb_sig']);
unset($_SESSION['fb_canvas_fb_params']);
exit();
}
else if (fb_canvas_is_iframe()) {
// Add to session paramaters that iframes will need.
if (!isset($_SESSION['fb_canvas_fb_sig'])) {
$_SESSION['fb_canvas_fb_params'] = $GLOBALS['_fb']->get_valid_fb_params($_REQUEST);
$_SESSION['fb_canvas_fb_sig'] = $_REQUEST['fb_sig'];
}
if (module_exists('fb_connect')) {
// Resize the iframe.
fb_connect_require_feature('CanvasUtil');
fb_connect_init_js("FB.CanvasClient.startTimerToSizeToContent();");
}
}
}
function fb_canvas_iframe_excursion_end() {
//fb_settings(FB_SETTINGS_CB, NULL);
//fb_settings(FB_SETTINGS_CB_SESSION, NULL);
}
// Recent changes may have broken the "old way".
function _fb_canvas_make_form_action_local($action = NULL) {
global $base_path;
if (!isset($action)) {
// Is this ever reached?
if (function_exists('dpm')) dpm("_fb_canvas_make_form_action_local($action)"); // XXX
$action = $_GET['q'];
}
// If action is fully qualified, do not change it
if (strpos($action, ':')) {
if (function_exists('dpm')) dpm($action, "leaving form action untouched"); // XXX
return $action;
}
// I'm not sure where the problem is, but sometimes actions have two question marks. I.e.
// /htdocs/?app=foo&q=user/login?destination=comment/reply/1%2523comment-form
// Here we replace 3rd (or more) '?' with '&'.
$parts = explode('?', $action);
if (count($parts) > 2) {
if (fb_verbose()) {
watchdog('fb_canvas', "fixing badly formed action: " . $action);
}
$action = array_shift($parts) . '?' . array_shift($parts);
$action .= '&' . implode('&', $parts);
}
$relative = url('');
$absolute = url('', array('absolute' => TRUE));
$base_path = base_path(); // By default, '#action' will be request_uri(), which starts with base_path();
global $_fb_app;
if (strpos($action, FB_SETTINGS_CB)) { // XXX old way. Will go away.
$action = $absolute . substr($action, strlen($relative));
}
elseif (strpos($action, $relative) === 0 && function_exists('fb_url_inbound_alter')) { // XXX another old way.
// Replace relative action with absolute.
// Include fb settings
// TODO: FB_SETTINGS_CB_TYPE
$action = $absolute . FB_SETTINGS_CB . '/' . $_fb_app->label . '/' . substr($action, strlen($relative));
}
else {
// New way...
if (strpos($action, $relative) === 0) {
// If here, the action was made by call to url() and we prepended
// canvas_name. Now remove the canvas name for a proper absolute url.
// (Comment forms reach this clause but node forms do not.)
$action = substr($action, strlen($relative));
}
elseif ($base_path && strpos($action, $base_path) === 0) {
$action = substr($action, strlen($base_path));
}
$action = url(ltrim($action, '/'), array('absolute' => TRUE));
}
// Changed code to work when $base_path set. Need to test on server where base_path is ''.
//dpm($action, "_fb_canvas_make_form_action_local returning
");
return $action;
}
/**
* Uses $_fb->redirect on canvas pages, otherwise drupal_goto.
*/
function fb_canvas_goto($path) {
global $_fb, $_fb_app;
if ($_fb && (fb_canvas_is_fbml() || fb_canvas_is_iframe())) {
$url = fb_canvas_fix_url(url($path, array('absolute' => TRUE)), $_fb_app);
// Allow modules to react to the end of the page request before redirecting.
// We do not want this while running update.php.
if (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE != 'update') {
$GLOBALS['_fb_canvas_goto'] = TRUE; // prevents fb_canvas_exit from calling redirect.
module_invoke_all('exit', $url);
}
$_fb->redirect($url);
}
else {
drupal_goto($path);
}
exit;
}
/**
* Convert a local fully qualified path to a facebook app path. This needs to
* be used internally, to fix drupal_gotos upon form submission. Third party
* modules should not need to call this.
*/
function fb_canvas_fix_url($url, $fb_app) {
//dpm(debug_backtrace(), "fb_canvas_fix_url($url)");
global $base_url;
// Url rewrites still used for iframe excursions.
$patterns[] = "|{$base_url}/" . FB_SETTINGS_CB . "/{$fb_app->label}/|";
// Here we hard-wire apps.facebook.com. Is there an API to get that?
$replacements[] = "http://apps.facebook.com/{$fb_app->canvas}/";
// Page type helps themes support multiple iframes.
$patterns[] = "|" . FB_SETTINGS_CB_TYPE . "/[^/]*/|";
$replacements[] = "";
$patterns[] = "|" . FB_SETTINGS_CB_SESSION . "/[^/]*/|";
$replacements[] = "";
// Fully qualified paths.
$patterns[] = "|" . url('', array('absolute' => TRUE)) . "|";
$replacements[] = "http://apps.facebook.com/{$fb_app->canvas}/";
// Facebook will prepend "appNNN_" all our ids
$patterns[] = "|#([^\?]*)|";
$replacements[] = "#app{$fb_app->id}_$1";
$url = preg_replace($patterns, $replacements, $url);
return $url;
}
/**
* Define custom_url_rewrite_outbound() if not defined already.
*/
if (!function_exists('custom_url_rewrite_outbound')) {
function custom_url_rewrite_outbound(&$path, &$options, $original_path) {
fb_canvas_url_outbound_alter($path, $options, $original_path);
}
}
function fb_canvas_url_outbound_alter(&$path, &$options, $original_path) {
global $_fb, $_fb_app;
if ($_fb_app && $_fb_app->canvas) {
if (fb_canvas_is_fbml()) {
if (!$options['absolute']) {
if (FALSE && file_exists($path)) { // Disabled on purpose
// This is disabled because Drupal is unlikely to honor the changes
// we make here. Sadly, routines like theme_image() do not honor url
// alters.
// Make absolute link to local file.
$options['absolute'] = TRUE;
}
else {
// Make a relative link to the application.
// base_path is not in options, so we kludge a faux absolute url.
$options['base_url'] = '/' . $_fb_app->canvas;
$options['absolute'] = TRUE;
// Note that facebook will prepend canvas_name to our relative url.
}
}
}
else if (fb_canvas_is_iframe()) {
if (!$options['absolute']) {
// Could append all 'fb_sig' params to internal links. But for now we rely on fb_canvas_process.
}
}
// Drupal has a habit of adding ?destination=... to some URLs.
// And Facebook for no good reason screws up when you do that.
if ($options['query']) {
$options['query'] = str_replace('destination=', 'fb_canvas_destination=', $options['query']);
}
}
}
/**
* This function uses regular expressions to convert links on canvas pages
* to URLs that begin http://apps.facebook.com/...
*
* Call this method from themes when producing either FBML or iframe canvas
* pages. This is a relatively expensive operation. Its unfortunate that we
* must do it on every page request. However to the best of my knowledge,
* Drupal provides no better way.
*
* In Drupal 7.x, there should be a way to alter URLs before they are
* rendered. That could provide a more efficient solution. Until
* then we are stuck with this.
*
* @param $output is the page (or iframe block) about to be returned.
*
* @param $options - 'add_target' will cause target=_top to be added
* when producing an iframe. 'force_absolute_canvas' will turn
* relative urls for canvas pages into absolute, for use on profile
* tabs.
*
*/
function fb_canvas_process($output, $options = array()) {
global $base_url;
global $_fb, $_fb_app;
$patterns = array();
$replacements = array();
$base_path = base_path();
if ($_fb) {
if (function_exists('fb_url_outbound_alter')) {
$base_before_rewrite = '';
$rewrite_options = array();
$base = $base_path . fb_url_outbound_alter($base_before_rewrite, $rewrite_options, ''); // short URL with rewrite applied.
}
else {
// Paving the way to make url alters optional. (may not work properly)
$base = $base_path;
//print("in fb_canvas_process, base is '$base'.");
}
if (fb_canvas_is_fbml()) {
//dpm($output, "before fb_canvas_process");
// We're producing FBML for a canvas page
// Fix for relative images
$absolute_base = url('', array('absolute' => TRUE));
$patterns[] = "|src=\"{$base}|";
$replacements[] = "src=\"$absolute_base";
// This fixes places in drupal that use base_url() . something, instead of calling url().
// including links to stylesheets and such.
$pattern = "|href=\"{$base}(?!" . preg_quote($_fb_app->canvas) . ")|";
//print ("pattern is $pattern \n\n"); // debug
$patterns[] = $pattern;
$replacements[] = "href=\"$absolute_base";
// This is needed under the old url rewriting scheme.
// Hope to do away with this for good eventually! XXX
if (isset($options['force_absolute_canvas']) && $options['force_absolute_canvas'] &&
$base != '/') {
// Change links to use canvas on Facebook
// Links ending in #something:
$patterns[] = "|=\"{$base}([^\"]*#)|";
$replacements[] = "=\"http://apps.facebook.com/{$_fb_app->canvas}/$1app{$_fb_app->id}_";
// Other links
$patterns[] = "|=\"{$base}|";
$replacements[] = "=\"http://apps.facebook.com/{$_fb_app->canvas}/";
}
/*
else {
// Change links to use canvas on Facebook
// Links ending in #something:
$patterns[] = "|=\"{$base}([^\"]*#)|";
$replacements[] = "=\"/{$_fb_app->canvas}/$1app{$_fb_app->id}_";
// Other links
$patterns[] = "|=\"{$base}|";
$replacements[] = "=\"/{$_fb_app->canvas}/";
}
// Change paths to files to fully qualified URLs. This matches relative
// URLs that do not include the canvas (that is, not matched by previous
// patterns).
if ($base_path != "/{$_fb_app->canvas}/") {
$patterns[] = '|="'. $base_path . "(?!{$_fb_app->canvas})|";
$replacements[] = '="'. $base_url .'/';
}
*/
// Experimental! Change 1234@facebook to an tag. This is our
// default user name convention when creating new users. Ideally, this
// would be accomplished with something like:
// http://drupal.org/node/102679. In the meantime, this may help for
// canvas pages only.
// Regexp avoids "1234@facebook" (surrounded by quotes) because
// that can appear in forms and FBML tags. Also avoids
// 1234@facebook.com, which can also appear in forms because it
// is used in authmaps. TODO: investigate the efficiency of
// this regexp (and/or make it optional)
$patterns[] = '|(?';
}
elseif (fb_canvas_is_iframe()) {
// Add target=_top so that entire pages do not appear within an iframe.
// TODO: make these pattern replacements more sophisticated, detect whether target is already set.
if (isset($options['add_target']) && $options['add_target']) {
// Add target=_top to all links
$patterns[] = "|]*)href=\"|";
$replacements[] = "]*)action=\"([^:\"]*):|";
$replacements[] = "