| 1 |
<?php
|
| 2 |
/**
|
| 3 |
* @file
|
| 4 |
*
|
| 5 |
* This module provides some app-specific navigation to facebook apps. This
|
| 6 |
* is fairly experimental material. May change a lot in near future.
|
| 7 |
*
|
| 8 |
*/
|
| 9 |
|
| 10 |
function fb_canvas_menu() {
|
| 11 |
$items = array();
|
| 12 |
if ($may_cache) {
|
| 13 |
$items['fb/canvas/session'] = array(
|
| 14 |
'page callback' => 'fb_canvas_session_cb',
|
| 15 |
'type' => MENU_CALLBACK,
|
| 16 |
'access callback' => TRUE,
|
| 17 |
);
|
| 18 |
}
|
| 19 |
return $items;
|
| 20 |
}
|
| 21 |
|
| 22 |
/**
|
| 23 |
* implementation of hook_block
|
| 24 |
*
|
| 25 |
* Block 0 is a session helper block. It is useful on FBML canvas
|
| 26 |
* pages. In includes an iframe, so the user's browser makes a
|
| 27 |
* request directly to the server, rather than via facebook. This
|
| 28 |
* will set a cookie on the browser, so that subsequent requests to
|
| 29 |
* the local server will share the same session as the canvas pages.
|
| 30 |
*
|
| 31 |
* Note that some browsers (safari) simply refuse to accept cookies
|
| 32 |
* from an iframe unless the user takes some action in that frame. In
|
| 33 |
* such a case this block will have no effect. If you encounter this,
|
| 34 |
* consider setting $conf['fb_session_cookieless_iframe'] = TRUE in
|
| 35 |
* your settings.php.
|
| 36 |
*/
|
| 37 |
function fb_canvas_block($op = 'list', $delta = 0, $edit = array()) {
|
| 38 |
if ($op == 'list') {
|
| 39 |
$items[0]['info'] = t('Facebook Canvas Session Helper');
|
| 40 |
return $items;
|
| 41 |
}
|
| 42 |
else if ($op == 'view') {
|
| 43 |
// This block only makes sense in FBML pages.
|
| 44 |
if (!fb_canvas_is_fbml()) {
|
| 45 |
return;
|
| 46 |
}
|
| 47 |
// Try to avoid including the iframe on every page, but use it if the currenly known session will expire soon.
|
| 48 |
if ($_SESSION['fb_canvas_session'] &&
|
| 49 |
$_SESSION['fb_frame_params'] &&
|
| 50 |
$_SESSION['fb_frame_params']['expires'] > time() + (60 * 60)) {
|
| 51 |
return;
|
| 52 |
}
|
| 53 |
$_SESSION['fb_canvas_session'] = TRUE;
|
| 54 |
|
| 55 |
$url = url('fb/canvas/session', array('absolute' => TRUE));
|
| 56 |
return array('subject' => NULL,
|
| 57 |
'content' => "<fb:iframe width=0 height=0 frameborder=0 src=$url></fb:iframe>");
|
| 58 |
}
|
| 59 |
}
|
| 60 |
|
| 61 |
/**
|
| 62 |
* Implementation of hook_fb.
|
| 63 |
*/
|
| 64 |
function fb_canvas_fb($op, $data, &$return) {
|
| 65 |
$fb = $data['fb'];
|
| 66 |
$fb_app = $data['fb_app'];
|
| 67 |
|
| 68 |
if ($op == FB_OP_CURRENT_APP) {
|
| 69 |
if ($apikey = $_REQUEST[FB_APP_REQ_API_KEY]) {
|
| 70 |
// If facebook has passed the app key, let's use that.
|
| 71 |
$fb_app = fb_get_app(array('apikey' => $apikey));
|
| 72 |
}
|
| 73 |
else {
|
| 74 |
if (function_exists('fb_settings')) {
|
| 75 |
// See fb_settings.inc
|
| 76 |
if ($nid = fb_settings(FB_SETTINGS_APP_NID)) {
|
| 77 |
// Here if we're in iframe, using our /fb_canvas/nid/ path convention.
|
| 78 |
$fb_app = fb_get_app(array('nid' => $nid));
|
| 79 |
}
|
| 80 |
}
|
| 81 |
}
|
| 82 |
if ($fb_app)
|
| 83 |
$return = $fb_app;
|
| 84 |
}
|
| 85 |
else if ($op == FB_OP_INITIALIZE) {
|
| 86 |
// Get our configuration settings.
|
| 87 |
$fb_app_data = fb_app_get_data($fb_app);
|
| 88 |
$fb_canvas_data = $fb_app_data['fb_canvas'];
|
| 89 |
|
| 90 |
$is_canvas = FALSE;
|
| 91 |
|
| 92 |
// Set an app-specific theme.
|
| 93 |
global $custom_theme; // Set by this function.
|
| 94 |
if (fb_canvas_is_fbml()) {
|
| 95 |
$custom_theme = $fb_canvas_data['theme_fbml'];
|
| 96 |
$is_canvas = TRUE;
|
| 97 |
}
|
| 98 |
else if (fb_canvas_is_iframe()) {
|
| 99 |
$custom_theme = $fb_canvas_data['theme_iframe'];
|
| 100 |
$is_canvas = TRUE;
|
| 101 |
}
|
| 102 |
|
| 103 |
// Special handling for forms, as they are submitted directly to us, not
|
| 104 |
// to apps.facebook.com/canvas
|
| 105 |
// we will buffer, and later cache, the results.
|
| 106 |
if (fb_canvas_handling_form())
|
| 107 |
ob_start();
|
| 108 |
|
| 109 |
if ($is_canvas && $_GET['q'] == drupal_get_normal_path(variable_get('site_frontpage', 'node'))) {
|
| 110 |
if ($fb->get_loggedin_user()) {
|
| 111 |
if ($fb->api_client->users_isAppUser())
|
| 112 |
$front = $fb_canvas_data['front_added'];
|
| 113 |
else
|
| 114 |
$front = $fb_canvas_data['front_loggedin'];
|
| 115 |
}
|
| 116 |
else
|
| 117 |
$front = $fb_canvas_data['front_anonymous'];
|
| 118 |
|
| 119 |
if ($front)
|
| 120 |
menu_set_active_item(drupal_get_normal_path($front));
|
| 121 |
}
|
| 122 |
}
|
| 123 |
else if ($op == FB_OP_EXIT) {
|
| 124 |
$destination = $return;
|
| 125 |
if (fb_canvas_handling_form() && $fb_app) {
|
| 126 |
$output = ob_get_contents();
|
| 127 |
ob_end_clean();
|
| 128 |
|
| 129 |
if ($destination) {
|
| 130 |
watchdog('fb_debug', "FB_OP_EXIT, handling form, original destination: $destination");
|
| 131 |
// Fully qualified URLs need to be modified to point to facebook app.
|
| 132 |
// URLs are fully qualified when a form submit handler returns a path,
|
| 133 |
// or any call to drupal_goto.
|
| 134 |
$destination = fb_canvas_fix_url($destination, $fb_app);
|
| 135 |
|
| 136 |
// If here, drupal_goto has been called, but it may not work within a
|
| 137 |
// canvas page, so we'll use Facebook's method.
|
| 138 |
// Will this preempt other hook_exits?
|
| 139 |
if ($fb) {
|
| 140 |
watchdog('fb_debug', "FB_OP_EXIT, handling form, redirecting to $destination");
|
| 141 |
$fb->redirect($destination);
|
| 142 |
}
|
| 143 |
}
|
| 144 |
else {
|
| 145 |
// Save the results to show the user later
|
| 146 |
$token = uniqid('fb_');
|
| 147 |
$cid = session_id() . "_$token";
|
| 148 |
watchdog('fb', "Storing cached form page $cid, then redirecting");
|
| 149 |
cache_set($cid, $output, 'cache_page', time() + (60 * 5), drupal_get_headers()); // (60 * 5) == 5 minutes
|
| 150 |
|
| 151 |
$dest = 'http://apps.facebook.com/' . $fb_app->canvas . "/fb/form_cache/$cid";
|
| 152 |
// $fb->redirect($url); // Does not work!
|
| 153 |
|
| 154 |
// Preserve some URL parameters
|
| 155 |
$query = array();
|
| 156 |
foreach (array('fb_force_mode') as $key) {
|
| 157 |
if ($_REQUEST[$key])
|
| 158 |
$query[] = $key . '=' . $_REQUEST[$key];
|
| 159 |
}
|
| 160 |
|
| 161 |
//drupal_goto honors $_REQUEST['destination'], but we only want that when no errors occurred
|
| 162 |
if (form_get_errors()) {
|
| 163 |
unset($_REQUEST['destination']);
|
| 164 |
if ($_REQUEST['edit'])
|
| 165 |
unset($_REQUEST['edit']['destination']);
|
| 166 |
}
|
| 167 |
|
| 168 |
drupal_goto($dest, implode('&', $query), NULL, 303); // appears to work
|
| 169 |
}
|
| 170 |
}
|
| 171 |
}
|
| 172 |
else if ($op == FB_OP_SET_PROPERTIES) {
|
| 173 |
// Compute properties which we can set automatically.
|
| 174 |
$callback_url = url('',array('absolute' => TRUE)) . FB_SETTINGS_APP_NID . '/' . $fb_app->nid . '/';
|
| 175 |
$return['callback_url'] = $callback_url;
|
| 176 |
}
|
| 177 |
else if ($op == FB_OP_LIST_PROPERTIES) {
|
| 178 |
$return[t('Callback URL')] = 'callback_url';
|
| 179 |
$return[t('Canvas Page Suffix')] = 'canvas_name';
|
| 180 |
}
|
| 181 |
}
|
| 182 |
|
| 183 |
|
| 184 |
/**
|
| 185 |
* Implementation of hook_form_alter.
|
| 186 |
*/
|
| 187 |
function fb_canvas_form_alter(&$form, &$form_state, $form_id) {
|
| 188 |
// Add our settings to the fb_app edit form.
|
| 189 |
if (is_array($form['fb_app_data'])) {
|
| 190 |
$node = $form['#node'];
|
| 191 |
$fb_app_data = fb_app_get_data($node->fb_app);
|
| 192 |
$fb_canvas_data = $fb_app_data['fb_canvas'];
|
| 193 |
|
| 194 |
// defaults
|
| 195 |
if (!$fb_canvas_data)
|
| 196 |
$fb_canvas_data = array();
|
| 197 |
$fb_canvas_data = array_merge(array('theme_fbml' => 'fb_fbml',
|
| 198 |
'theme_iframe' => 0),
|
| 199 |
$fb_canvas_data);
|
| 200 |
|
| 201 |
|
| 202 |
$form['fb_app_data']['fb_canvas'] = array('#type' => 'fieldset',
|
| 203 |
'#collapsible' => TRUE,
|
| 204 |
'#collapsed' => TRUE,
|
| 205 |
'#title' => t('Facebook canvas page settings'),
|
| 206 |
'#description' => t('Allows application-specific front page and navigation links.')
|
| 207 |
);
|
| 208 |
$form['fb_app_data']['fb_canvas']['front_anonymous'] =
|
| 209 |
array('#type' => 'textfield',
|
| 210 |
'#title' => t('Front page when user is not logged in to facebook'),
|
| 211 |
'#description' => t('Leave blank to use the site-wide front page. See <a href="!link" target=_blank>Public Canvas Pages</a>.',
|
| 212 |
array('!link' => 'http://wiki.developers.facebook.com/index.php/Public_Canvas_Pages')),
|
| 213 |
'#default_value' => $fb_canvas_data['front_anonymous'],
|
| 214 |
);
|
| 215 |
$form['fb_app_data']['fb_canvas']['front_loggedin'] =
|
| 216 |
array('#type' => 'textfield',
|
| 217 |
'#title' => t('Front page when user is logged in to facebook, but is not a user of the app'),
|
| 218 |
'#description' => t('Leave blank to use the site-wide front page.'),
|
| 219 |
'#default_value' => $fb_canvas_data['front_loggedin'],
|
| 220 |
);
|
| 221 |
$form['fb_app_data']['fb_canvas']['front_added'] =
|
| 222 |
array('#type' => 'textfield',
|
| 223 |
'#title' => t('Front page for users of this application'),
|
| 224 |
'#description' => t('Leave blank to use the site-wide front page.'),
|
| 225 |
'#default_value' => $fb_canvas_data['front_added'],
|
| 226 |
);
|
| 227 |
|
| 228 |
/* XXX menu code here needs updating to D6
|
| 229 |
// Allow primary links to be different on facebook versus the rest of the
|
| 230 |
// site. Code from menu_configure() in menu.module.
|
| 231 |
|
| 232 |
$primary = variable_get('menu_primary_links_source', 'primary-links');
|
| 233 |
$primary_options = array_merge($menu_options, array('' => t('<use sitewide setting>')));
|
| 234 |
$form['fb_app_data']['fb_canvas']['menu_primary_links_source'] =
|
| 235 |
array(
|
| 236 |
'#type' => 'select',
|
| 237 |
'#title' => t('Source for the primary links'),
|
| 238 |
'#default_value' => $fb_canvas_data['primary_links'],
|
| 239 |
'#options' => $primary_options,
|
| 240 |
'#tree' => FALSE,
|
| 241 |
'#description' => t('Your application can have primary links different from those used elsewhere on your site.'),
|
| 242 |
);
|
| 243 |
|
| 244 |
$secondary_options = array_merge($menu_options, array('' => t('<use sitewide setting>')));
|
| 245 |
$form['fb_app_data']['fb_canvas']['menu_secondary_links_source'] =
|
| 246 |
array(
|
| 247 |
'#type' => 'select',
|
| 248 |
'#title' => t('Source for the secondary links'),
|
| 249 |
'#default_value' => $fb_canvas_data['secondary_links'],
|
| 250 |
'#options' => $secondary_options,
|
| 251 |
'#tree' => FALSE,
|
| 252 |
'#description' => t('If you select the same menu as primary links then secondary links will display the appropriate second level of your navigation hierarchy.'),
|
| 253 |
);
|
| 254 |
*/
|
| 255 |
|
| 256 |
// Override themes
|
| 257 |
$themes = system_theme_data();
|
| 258 |
ksort($themes);
|
| 259 |
$theme_options[0] = t('System default');
|
| 260 |
foreach ($themes as $theme) {
|
| 261 |
$theme_options[$theme->name] = $theme->name;
|
| 262 |
}
|
| 263 |
$form['fb_app_data']['fb_canvas']['theme_fbml'] =
|
| 264 |
array('#type' => 'select',
|
| 265 |
'#title' => t('Theme for FBML pages'),
|
| 266 |
'#description' => t('Choose only a theme that is FBML-aware.'),
|
| 267 |
'#options' => $theme_options,
|
| 268 |
'#required' => TRUE,
|
| 269 |
'#default_value' => $fb_canvas_data['theme_fbml'],
|
| 270 |
);
|
| 271 |
$form['fb_app_data']['fb_canvas']['theme_iframe'] =
|
| 272 |
array('#type' => 'select',
|
| 273 |
'#title' => t('Theme for iframe pages'),
|
| 274 |
'#description' => t('Choose only a facebook-aware theme'),
|
| 275 |
'#options' => $theme_options,
|
| 276 |
'#required' => TRUE,
|
| 277 |
'#default_value' => $fb_canvas_data['theme_iframe'],
|
| 278 |
);
|
| 279 |
}
|
| 280 |
|
| 281 |
|
| 282 |
global $fb, $fb_app;
|
| 283 |
// We will send all form submission directly to us, not via
|
| 284 |
// apps.facebook.com/whatever.
|
| 285 |
if (fb_canvas_is_fbml()) {
|
| 286 |
//dpm($form, "fb_canvas_form_alter($form_id)"); // debug
|
| 287 |
|
| 288 |
// We're in a facebook callback
|
| 289 |
|
| 290 |
if (!isset($form['fb_canvas_form_handler'])) {
|
| 291 |
$form['fb_canvas_form_handler'] = array();
|
| 292 |
|
| 293 |
// This variable tells us to handle the form on submit.
|
| 294 |
// Can't use 'fb_handling_form' because facebook strips it.
|
| 295 |
$form['fb_canvas_form_handler']['_fb_handling_form'] = array('#value' => TRUE,
|
| 296 |
'#type' => 'hidden');
|
| 297 |
|
| 298 |
// We need to make sure the action goes to our domain and not apps.facebook.com, so here we tweak the form action.
|
| 299 |
$form['fb_canvas_form_handler']['#action_old'] = $form['action'];
|
| 300 |
if ($form['#action'] == '') {
|
| 301 |
$form['#action'] = $_GET['q'];
|
| 302 |
}
|
| 303 |
$form['#action'] = _fb_canvas_make_form_action_local($form['#action']);
|
| 304 |
$form['fb_canvas_form_handler']['#action_new'] = $form['#action'];
|
| 305 |
// We've stored #action_old and #action_new so custom modules have the option to change it back.
|
| 306 |
}
|
| 307 |
|
| 308 |
// Drupal includes wacky markup for javascript junk in node forms. It
|
| 309 |
// makes things look terrible in FBML. It only works when javascript is
|
| 310 |
// enabled and it should have been implemented to degrade gracefully, but
|
| 311 |
// it wasn't.
|
| 312 |
if ($form['body_field']) {
|
| 313 |
unset($form['body_field']['teaser_js']);
|
| 314 |
unset($form['body_field']['teaser_include']);
|
| 315 |
}
|
| 316 |
|
| 317 |
}
|
| 318 |
else if (fb_canvas_is_iframe()) {
|
| 319 |
//dpm($form, 'fb_canvas_form_alter');
|
| 320 |
}
|
| 321 |
}
|
| 322 |
|
| 323 |
/**
|
| 324 |
* Call this from your form_alter hook to prevent changes to the
|
| 325 |
* form's default action.
|
| 326 |
*/
|
| 327 |
function fb_canvas_form_action_via_facebook(&$form) {
|
| 328 |
if ($form['fb_canvas_form_handler']) {
|
| 329 |
$form['#action'] = $form['fb_canvas_form_handler']['#action_old'];
|
| 330 |
}
|
| 331 |
$form['fb_canvas_form_handler'] = array();
|
| 332 |
}
|
| 333 |
|
| 334 |
function fb_canvas_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
|
| 335 |
if ($op == 'view' && $node->type == 'fb_app') {
|
| 336 |
if (user_access('administer fb apps') && $node->fb_app->canvas) {
|
| 337 |
$fb_app = $node->fb_app;
|
| 338 |
$url = 'http://apps.facebook.com/' . $fb_app->canvas;
|
| 339 |
$output = theme('dl',
|
| 340 |
array(t('Canvas URL') => l($url, $url, array('attributes' => array('target' => '_blank'))),
|
| 341 |
));
|
| 342 |
|
| 343 |
$node->content['fb_canvas'] =
|
| 344 |
array('#value' => $output,
|
| 345 |
'#weight' => 2);
|
| 346 |
}
|
| 347 |
}
|
| 348 |
}
|
| 349 |
|
| 350 |
|
| 351 |
/**
|
| 352 |
* Implementation of hook_footer().
|
| 353 |
*
|
| 354 |
* Invoke FB_OP_CANVAS_FBJS_INIT, allowing other modules to insert
|
| 355 |
* FBJS to the current page.
|
| 356 |
*/
|
| 357 |
function fb_canvas_footer($main = 0) {
|
| 358 |
if (fb_canvas_is_fbml()) {
|
| 359 |
// Add FBJS only to FBML pages.
|
| 360 |
global $fb, $fb_app;
|
| 361 |
$data = array('fb' => $fb, 'fb_app' => $fb_app);
|
| 362 |
$extra = fb_invoke(FB_OP_CANVAS_FBJS_INIT, $data, array());
|
| 363 |
//dpm($extra, "FB_OP_CANVAS_FBJS_INIT returning"); // XXX
|
| 364 |
if (count($extra)) {
|
| 365 |
$extra_js = implode("\n", $extra);
|
| 366 |
fb_add_js('', ''); // prime javascript
|
| 367 |
drupal_add_js($extra_js, 'inline', 'fbml');
|
| 368 |
}
|
| 369 |
}
|
| 370 |
}
|
| 371 |
|
| 372 |
|
| 373 |
function fb_canvas_is_fbml() {
|
| 374 |
global $fb, $fb_app;
|
| 375 |
if ($fb && $fb_app) {
|
| 376 |
// Facebook events are not canvas pages
|
| 377 |
if (arg(0) == 'fb_app' && arg(1) == 'event')
|
| 378 |
return FALSE;
|
| 379 |
else
|
| 380 |
return ($fb->in_fb_canvas() || fb_canvas_handling_form());
|
| 381 |
}
|
| 382 |
}
|
| 383 |
|
| 384 |
function fb_canvas_is_iframe() {
|
| 385 |
global $fb, $fb_app;
|
| 386 |
if ($fb && $fb_app) {
|
| 387 |
return ($fb->in_frame() && !fb_canvas_is_fbml());
|
| 388 |
}
|
| 389 |
}
|
| 390 |
|
| 391 |
function fb_canvas_handling_form() {
|
| 392 |
global $fb;
|
| 393 |
|
| 394 |
// Test whether a form has been submitted via facebook canvas page.
|
| 395 |
if ($fb && $_REQUEST['form_id'] && $_REQUEST['_fb_handling_form'])
|
| 396 |
return TRUE;
|
| 397 |
}
|
| 398 |
|
| 399 |
|
| 400 |
// This may need work
|
| 401 |
function _fb_canvas_make_form_action_local($action) {
|
| 402 |
//dpm($action, "_fb_canvas_make_form_action_local");
|
| 403 |
global $base_path;
|
| 404 |
|
| 405 |
// If action is fully qualified, do not change it
|
| 406 |
if (strpos($action, ':'))
|
| 407 |
return $action;
|
| 408 |
|
| 409 |
// I'm not sure where the problem is, but sometimes actions have two question marks. I.e.
|
| 410 |
// /htdocs/?app=foo&q=user/login?destination=comment/reply/1%2523comment-form
|
| 411 |
// Here we replace 3rd (or more) '?' with '&'.
|
| 412 |
$parts = explode('?', $action);
|
| 413 |
if (count($parts) > 2) {
|
| 414 |
$action = array_shift($parts) . '?' . array_shift($parts);
|
| 415 |
$action .= '&' . implode('&', $parts);
|
| 416 |
}
|
| 417 |
|
| 418 |
$relative = url('');
|
| 419 |
$absolute = url('', array('absolute'=>TRUE));
|
| 420 |
global $fb_app;
|
| 421 |
|
| 422 |
if (strpos($action, FB_SETTINGS_APP_NID)) {
|
| 423 |
$action = $absolute . substr($action, strlen($relative));
|
| 424 |
}
|
| 425 |
else if (strpos($action, $relative) === 0) {
|
| 426 |
// Replace relative action with absolute.
|
| 427 |
// Include fb settings
|
| 428 |
// TODO: FB_SETTINGS_PAGE_TYPE
|
| 429 |
$action = $absolute . FB_SETTINGS_APP_NID . '/' . $fb_app->nid . '/' . substr($action, strlen($relative));
|
| 430 |
}
|
| 431 |
|
| 432 |
//dpm($action, '_fb_canvas_make_form_action_local returning');
|
| 433 |
return $action;
|
| 434 |
|
| 435 |
//drupal_set_message("form action now " . "http://".$_SERVER['HTTP_HOST']. $action); // debug
|
| 436 |
//return "http://".$_SERVER['HTTP_HOST']. $action;
|
| 437 |
}
|
| 438 |
|
| 439 |
/**
|
| 440 |
* Uses $fb->redirect on canvas pages, otherwise drupal_goto.
|
| 441 |
*/
|
| 442 |
function fb_canvas_goto($path) {
|
| 443 |
global $fb, $fb_app;
|
| 444 |
if ($fb && (fb_canvas_is_fbml() || fb_canvas_is_iframe())) {
|
| 445 |
$url = fb_canvas_fix_url(url($path, array('absolute' => TRUE)), $fb_app);
|
| 446 |
$fb->redirect($url);
|
| 447 |
}
|
| 448 |
else {
|
| 449 |
drupal_goto($path);
|
| 450 |
}
|
| 451 |
exit;
|
| 452 |
}
|
| 453 |
|
| 454 |
|
| 455 |
/**
|
| 456 |
* Convert a local fully qualified path to a facebook app path. This needs to
|
| 457 |
* be used internally, to fix drupal_gotos upon form submission. Third party
|
| 458 |
* modules should not need to call this, I believe.
|
| 459 |
*/
|
| 460 |
function fb_canvas_fix_url($url, $fb_app) {
|
| 461 |
|
| 462 |
global $base_url;
|
| 463 |
|
| 464 |
|
| 465 |
$patterns[] = "|{$base_url}/" . FB_SETTINGS_APP_NID . "/{$fb_app->nid}/|";
|
| 466 |
// Here we assume apps.facebook.com. Is this safe?
|
| 467 |
$replacements[] = "http://apps.facebook.com/{$fb_app->canvas}/";
|
| 468 |
|
| 469 |
// fully qualified paths
|
| 470 |
$patterns[] = "|".url('', array('absolute' => TRUE))."|";
|
| 471 |
$replacements[] = "http://apps.facebook.com/{$fb_app->canvas}/";
|
| 472 |
|
| 473 |
|
| 474 |
$patterns[] = "|fb_cb_type/[^/]*/|";
|
| 475 |
$replacements[] = "";
|
| 476 |
|
| 477 |
// Facebook will prepend "appNNN_" all our ids
|
| 478 |
$patterns[] = "|#([^\?]*)|";
|
| 479 |
$replacements[] = "#app{$fb_app->id}_$1";
|
| 480 |
|
| 481 |
$url = preg_replace($patterns, $replacements, $url);
|
| 482 |
|
| 483 |
return $url;
|
| 484 |
}
|
| 485 |
|
| 486 |
/**
|
| 487 |
* Returns the 'type' of the page. This helps themes determine whether they
|
| 488 |
* are to provide an iframe or an iframe within FBML.
|
| 489 |
*/
|
| 490 |
function fb_canvas_page_type() {
|
| 491 |
return fb_settings(FB_SETTINGS_PAGE_TYPE);
|
| 492 |
}
|
| 493 |
|
| 494 |
function fb_canvas_primary_links() {
|
| 495 |
global $fb_app;
|
| 496 |
$mid = 0;
|
| 497 |
if ($fb_app) {
|
| 498 |
$fb_app_data = fb_app_get_data($fb_app);
|
| 499 |
$fb_canvas_data = $fb_app_data['fb_canvas'];
|
| 500 |
$mid = $fb_canvas_data['primary_links'];
|
| 501 |
}
|
| 502 |
if ($mid)
|
| 503 |
return menu_primary_links(1, $mid);
|
| 504 |
else
|
| 505 |
return menu_primary_links();
|
| 506 |
}
|
| 507 |
|
| 508 |
function fb_canvas_secondary_links() {
|
| 509 |
global $fb_app;
|
| 510 |
if ($fb_app) {
|
| 511 |
$fb_app_data = fb_app_get_data($fb_app);
|
| 512 |
$fb_canvas_data = $fb_app_data['fb_canvas'];
|
| 513 |
$mid1 = $fb_canvas_data['primary_links'];
|
| 514 |
$mid2 = $fb_canvas_data['secondary_links'];
|
| 515 |
}
|
| 516 |
if ($mid2) {
|
| 517 |
if ($mid2 == $mid1)
|
| 518 |
return menu_primary_links(2, $mid2);
|
| 519 |
else
|
| 520 |
return menu_primary_links(1, $mid2);
|
| 521 |
}
|
| 522 |
else
|
| 523 |
return menu_secondary_links();
|
| 524 |
}
|
| 525 |
|
| 526 |
/**
|
| 527 |
* This function uses regular expressions to convert links on canvas pages
|
| 528 |
* to URLs that begin http://apps.facebook.com/...
|
| 529 |
*
|
| 530 |
* Call this method from themes when producing either FBML or iframe canvas
|
| 531 |
* pages. This is a relatively expensive operation. Its unfortunate that we
|
| 532 |
* must do it on every page request. However to the best of my knowledge,
|
| 533 |
* Drupal provides no better way.
|
| 534 |
*
|
| 535 |
* @param $output is the page (or iframe block) about to be returned.
|
| 536 |
*
|
| 537 |
* @param $add_target will cause target=_top to be added when producing an
|
| 538 |
* iframe.
|
| 539 |
*
|
| 540 |
*/
|
| 541 |
function fb_canvas_process($output, $add_target = TRUE) {
|
| 542 |
global $base_path, $base_url;
|
| 543 |
global $fb, $fb_app;
|
| 544 |
|
| 545 |
$patterns = array();
|
| 546 |
$replacements = array();
|
| 547 |
|
| 548 |
if ($fb) {
|
| 549 |
$page_type = fb_settings(FB_SETTINGS_PAGE_TYPE);
|
| 550 |
$nid = $fb_app->nid;
|
| 551 |
$base_before_rewrite = '';
|
| 552 |
$rewrite_options = array();
|
| 553 |
$base = $base_path . fb_url_outbound_alter($base_before_rewrite, $rewrite_options, ''); // short URL with rewrite applied.
|
| 554 |
|
| 555 |
if (fb_canvas_is_fbml()) {
|
| 556 |
//dpm($output, "before fb_canvas_process");
|
| 557 |
// We're producing FBML for a canvas page
|
| 558 |
/*
|
| 559 |
TODO: $output['logo'] is not being processed properly by these
|
| 560 |
patterns. fb_canvas_process() returns '/sites/all/themes/fb_fbml/logo.png'
|
| 561 |
and Facebook complains "Relative URLs not allowed here"
|
| 562 |
|
| 563 |
*/
|
| 564 |
|
| 565 |
// Change links to use canvas on Facebook
|
| 566 |
// Links ending in #something:
|
| 567 |
$patterns[] = "|=\"{$base}([^\"]*#)|";
|
| 568 |
$replacements[] = "=\"/{$fb_app->canvas}/$1app{$fb_app->id}_";
|
| 569 |
// Other links
|
| 570 |
$patterns[] = "|=\"{$base}|";
|
| 571 |
$replacements[] = "=\"/{$fb_app->canvas}/";
|
| 572 |
|
| 573 |
// Workaround Drupal does not let us rewrite the frontpage url
|
| 574 |
/* Not needed thanks to: http://drupal.org/node/241878
|
| 575 |
$patterns[] = "|=\"{$base_path}\"|";
|
| 576 |
$replacements[] = "=\"/{$fb_app->canvas}/\"";
|
| 577 |
*/
|
| 578 |
|
| 579 |
// Change paths to files to fully qualified URLs. This matches relative
|
| 580 |
// URLs that do not include the canvas (that is, not matched by previous
|
| 581 |
// patterns).
|
| 582 |
if ($base_path != "/{$fb_app->canvas}/") {
|
| 583 |
$patterns[] = '|="'.$base_path."(?!{$fb_app->canvas})|";
|
| 584 |
$replacements[] = '="'.$base_url.'/';
|
| 585 |
}
|
| 586 |
|
| 587 |
// Experimental! Change 1234@facebook to an <fb:name> tag. This is our
|
| 588 |
// default user name convention when creating new users. Ideally, this
|
| 589 |
// would be accomplished with something like:
|
| 590 |
// http://drupal.org/node/102679. In the meantime, this may help for
|
| 591 |
// canvas pages only.
|
| 592 |
|
| 593 |
// Regexp avoids "1234@facebook" (surrounded by quotes) because that can
|
| 594 |
// appear in some forms. Also avoids 1234@facebook.com, which can also
|
| 595 |
// appear in forms because it is used in authmaps. TODO: investigate
|
| 596 |
// the efficiency of this regexp (and/or make it optional)
|
| 597 |
$patterns[] = '|(?<!["\d])([\d]*)@facebook(?!\.com)|';
|
| 598 |
$replacements[] = '<fb:name uid=$1 linked=false ifcantsee="$1@facebook" useyou=false />';
|
| 599 |
|
| 600 |
}
|
| 601 |
else if (fb_canvas_is_iframe()) {
|
| 602 |
// In iframe
|
| 603 |
// Add target=_top so that entire pages do not appear within an iframe.
|
| 604 |
// TODO: make these pattern replacements more sophisticated, detect whether target is already set.
|
| 605 |
if ($add_target) {
|
| 606 |
// Add target=_top to all links
|
| 607 |
$patterns[] = "|<a |";
|
| 608 |
$replacements[] = "<a target=\"_top\" ";
|
| 609 |
// Do not change local forms, but do change external ones
|
| 610 |
$patterns[] = "|<form([^>]*)action=\"([^:\"]*):|";
|
| 611 |
$replacements[] = "<form target=\"_top\" $1 action=\"$2:";
|
| 612 |
|
| 613 |
// Make internal links point to canvas pages
|
| 614 |
$patterns[] = "|<a([^>]*)href=\"{$base}|";
|
| 615 |
$replacements[] = "<a $1 href=\"http://apps.facebook.com/{$fb_app->canvas}/";
|
| 616 |
}
|
| 617 |
else {
|
| 618 |
// Add target=_top to only external links
|
| 619 |
$patterns[] = "|<a([^>]*)href=\"([^:\"]*):|";
|
| 620 |
$replacements[] = "<a target=\"_top\" $1 href=\"$2:";
|
| 621 |
$patterns[] = "|<form([^>]*)action=\"([^:\"]*):|";
|
| 622 |
$replacements[] = "<form target=\"_top\" $1 action=\"$2:";
|
| 623 |
}
|
| 624 |
|
| 625 |
// Workaround Drupal does not let us rewrite the frontpage url
|
| 626 |
//$patterns[] = "|=\"{$base_path}\"|";
|
| 627 |
//$replacements[] = "=\"{$base_path}fb_canvas/{$page_type}/{$nid}/\""; // XXX
|
| 628 |
}
|
| 629 |
}
|
| 630 |
if (count($patterns)) {
|
| 631 |
//dpm($patterns, "fb_canvas_process patterns");
|
| 632 |
//dpm($replacements, "fb_canvas_process replacements");
|
| 633 |
|
| 634 |
$return = preg_replace($patterns,
|
| 635 |
$replacements,
|
| 636 |
$output);
|
| 637 |
return $return;
|
| 638 |
}
|
| 639 |
else
|
| 640 |
return $output;
|
| 641 |
}
|
| 642 |
|
| 643 |
//This API needs testing and may need to be improved...
|
| 644 |
/**
|
| 645 |
* Similar to fb_canvas_process, this also uses regular expressions to alter
|
| 646 |
* link destinations. Use this function when producing FBML for a profile box
|
| 647 |
* or news feed, and the pages need to link to canvas pages rather than the
|
| 648 |
* default URL.
|
| 649 |
*
|
| 650 |
*/
|
| 651 |
function fb_canvas_process_fbml($output, $fb_app) {
|
| 652 |
$patterns = array();
|
| 653 |
$replacements = array();
|
| 654 |
|
| 655 |
$base = url(); // short URL with rewrite applied.
|
| 656 |
|
| 657 |
if ($fb_app->canvas) {
|
| 658 |
// Change links to use canvas on Facebook
|
| 659 |
$patterns[] = "|href=\"{$base}|";
|
| 660 |
$replacements[] = "href=\"http://apps.facebook.com/{$fb_app->canvas}/";
|
| 661 |
}
|
| 662 |
|
| 663 |
if (count($patterns)) {
|
| 664 |
$return = preg_replace($patterns,
|
| 665 |
$replacements,
|
| 666 |
$output);
|
| 667 |
|
| 668 |
return $return;
|
| 669 |
}
|
| 670 |
else
|
| 671 |
return $output;
|
| 672 |
}
|
| 673 |
|
| 674 |
?>
|