As you know, Facebook Connect and Facebook Iframe Aps restrict the developer to only using XFBML if the page is being served from somewhere outside of Facebook (as all iframes and connect applications are by definition)

Facebook does make available, however, a handy XFBML tag Fb:serverfbml that allows you to serve up regular FBML inside a Facebook served iframe within your non-FBML facebook application.

The example below shows how the fb:friend-selector FBML tag can be implemented in an iframe application. This example populate a friend selector and display’s that friend’s Facebook UserID when the post button is clicked.


<?php
//Link in library. Note my directory structure may be different
require_once '../fblibrary/facebook.php';

//Authentication Keys
//My Authentication Keys. Sored in $appapikey and $appsecret respectively
require_once 'keys.php';

//Construct the class
$facebook = new Facebook($appapikey, $appsecret);

//Require login
$user_id = $facebook->get_loggedin_user();
if (!$user_id>0) {
	$user_id = $facebook->require_login();
}

//Get the authentication variables
foreach($_GET as $key => $value) {
	if (strpos($key,"fb_sig")!==false) {
		if ($i!=0) $fbvars.= "&";
		$fbvars.= "$key=$value";
		$i++;
	}
}

?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:fb="http://www.facebook.com/2008/fbml">
<head></head> 

<body> 

<script src="http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php" type="text/javascript"></script> 

	<?=$_GET[friend_sel];?>

	<fb:serverfbml style="width: 500px; height:20px;">

		<script type="text/fbml">

		<form id="addform" action="http://www.keywordintellect.com/facebook/iframeexample/serverfbml.php?<?=fbvars?>">
			<fb:fbml>
				<fb:friend-selector uid="<?=$user_id?>" name="newuid" idname="friend_sel"></fb:friend-selector>
			</fb:fbml>
			<input type="submit" value="Submit"/>
		</form>

		</script>
	</fb:serverfbml>

<script type="text/javascript">  FB.init("<?=$appapikey?>", "xd_receiver.htm"); </script> 

</body>
</html>

This tutorial assumes you already have a basic Facebook IFrame application up and running. If not, see our getting started tutorial.

First, we need a javascript function or library to handle our Ajax requests. To keep it simple, and cross-browser compatible, we use the Prototype Javascript Library. Specifically the version that is hosted and maintained by Google. To implement, add this to your canvas page header:

	<script src="http://www.google.com/jsapi"></script>
	<script>
		// Load AJAX modules
	   	google.load("prototype", "1.6");
	</script>

Next, create a DIV on your page to hold our AJAX enabled content. For example:

<div id="comments">Populating Comments....</div>

We need to create a separate file for the AJAX call to fetch and use to populate the div. So create a new file (I used simpleajax_divcontent.php in my example). Add whatever you want to that file. I used:

<?

//If we don't sleep then the DIV populates too quickly to see anything
sleep(3);

echo "Here are the comments from the Ajax page";

?>

I call that sleep function because the div would update too quickly to even see it otherwise (obviously in a real application you wouldn’t need to use it)

Now, back to our canvas page. Before the closing body tag, add the following Javascript to call the Updater function from the Prototype library. Substitute your file name for my ’simpleajax…’ name.

<script type="text/javascript">
new Ajax.Updater('comments', 'simpleajax_divcontent.php', { method: 'get' });
</script>

You’re done! One note: if you want to make Facebook API or XFBML calls on the page you are calling from the code above, you have to pass the fb_sig GET variables through the url ’simpleajax_divcontent.php?fb_sig=adfafdfafdqaf’ etc. This keeps everything authenticated. See our other post on the topic for more info.

Getting Facebook Developer Application running and libraries installed:

Go to http://developers.facebook.com/ . Click the Green “Get Started”  Button

Click “PHP Client Libraries” on the right side of the page in the gray box. Save the zip file to your local computer. Unzip the contents of “facebook-platform”>>”php” and upload to the folder on your web server that will serve as the root of your Facebook application. FYI, you just need the files in the “php” folder in your root directory.

Install the Facebook developer application at http://www.facebook.com/developers/

Click the “Setup a new application” link in the gray box in the upper right of the developer application homepage

Fillout the application name and submit

Now you are on the edit application settings interface.

Click the “Canvas” tab on the left and change the following:

  • “Canvas Page Url” enter the url you want your application to be displayed under on facebook. I used “iframexample”.
  • Under “Canvas Callback URL”, enter the URL of the applications “homepage” on your server. I used “www.keywordintellect.com/facebook/iframeexample/”.
  • Under “Canvas Settings” click “IFrame”.

Click the “connect” tab on the same settings interface. In the “Connect URL” field enter your Canvas URL (http://www.keywordintellect.com/facebook/iframeexample/ in my case)

Save your settings

Setup your canvas page:

Create a file named “index.php” and put it in the root directory on your webserver for the application “www.keywordintellect.com/facebook/iframeexample/” in my case.

Call the Facebook libraries and authenticate. Note: Replace the app key and secret with the values displayed on your applications settings page withing Facebook. Note: that since I have many aps running, I separated out the Facebook Libraries in a separate directory up one level from my application roots

<?

//Link in library. Note my directory structure may be different
require_once '../fblibrary/facebook.php';

//Authentication Keys
$appapikey = 'REPLACE WITH YOUR KEY';
$appsecret = 'REPLACE WITH YOUR SECRET';

//Construct the class
$facebook = new Facebook($appapikey, $appsecret);

//Require login
$user_id = $facebook->require_login();
?>

Let’s also add in a basic XFBML call to the fb:name tag as well as an API call to get the UIDs of the logged in users friends

<?

// XFBML: Greet the currently logged-in user!
echo "<p>Hello, <fb:name uid=\"$user_id\" useyou=\"false\" ></fb:name>!</p>";

// API: Print out at most 25 of the logged-in user's friends, using the friends.get API method
echo "<p>Friends:";
$friends = $facebook->api_client->friends_get();
$friends = array_slice($friends, 0, 25);
foreach ($friends as $friend) {
  echo "<br>$friend";
}
echo "</p>";

?>

Now, if we were to stop here and run it, the API call would work, but the XFBML would not. We need to set up the page to handle the XFBML. The XFBML documentation is here: http://wiki.developers.facebook.com/index.php/XFBML.

First, you need to create a Cross Domain Communication Channel File. Follow these instructions: http://wiki.developers.facebook.com/index.php/Cross-domain_communication_channel

When that file is created, we then add the following code before and after the PHP XFBML. Note, you need to add your API key and change the path to the Cross Domain Channel File in the last line.

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:fb="http://www.facebook.com/2008/fbml">
<head>
</head>
<body>
<script src="http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php" type="text/javascript"></script>

<? //Insert the PHP XFBML and API PHP code above here ?>

<script type="text/javascript">
	FB.init("YOUR API KEY HERE", "../fblibrary/xd_receiver.htm"); });
</script>

</body>
</html>

Congrats, you are done!

Here is the full index.php file:

<?php
//Link in library. Note my directory structure may be different
require_once '../fblibrary/facebook.php';

//Authentication Keys
$appapikey = 'YOURAPIKEY';
$appsecret = 'YOURAPISECRET';

//Construct the class
$facebook = new Facebook($appapikey, $appsecret);

//Require login
$user_id = $facebook->require_login();
?>

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:fb="http://www.facebook.com/2008/fbml">
	<head>
	</head>
	<body>
		<script src="http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php" type="text/javascript"></script>

		<?
			// Greet the currently logged-in user!
			echo "<p>Hello, <fb:name uid=\"$user_id\" useyou=\"false\"></fb:name>!</p>";

			// Print out at most 25 of the logged-in user's friends, using the friends.get API method
			echo "<p>Friends:";
			$friends = $facebook->api_client->friends_get();
			$friends = array_slice($friends, 0, 25);
			foreach ($friends as $friend) {
			  echo "<br>$friend";
			}
			echo "</p>";
		?>

		<script type="text/javascript">
			FB.init("YOURAPIKEY", "../fblibrary/xd_receiver.htm");
		</script> 

	</body>
</html>
9 Jun, 2009  |  Written by Jon  |  under Facebook Development

Facebook has a great tool to debug API requests that is a bit tough to find / under documented. If you add the php code…

$GLOBALS['facebook_config']['debug']=true;

at the top of your page, and then make an api call to users->getinfo for example, then the debug tool outputs the following on your HTML page (inline, in a neat Ajax click to see details type box):

Params:

Array
(
    [uids] => 780432493
    [fields] => uid,first_name,last_name,name,locale,pic_square,profile_url
)

XML:

<?xml version="1.0" encoding="UTF-8"?>
<users_getInfo_response>
  <user>
    <uid>780432493</uid>
    <uid>780432493</uid>
    <first_name>Jon</first_name>
    <last_name>Pastor</last_name>
    <name>Jon Pastor</name>
    <locale>en_US</locale>
    <pic_square>http://profile.ak.facebook.com/v224/904/100/q780432493_3916.jpg</pic_square>
    <profile_url>http://www.facebook.com/profile.php?id=780432493</profile_url>
  </user>
</users_getInfo_response>

SXML:

SimpleXMLElement Object
(
    [@attributes] => Array
        (
            [list] => true
        )

    [user] => SimpleXMLElement Object
        (
            [uid] => Array
                (
                    [0] => 780432493
                    [1] => 780432493
                )

            [first_name] => Jon
            [last_name] => Pastor
            [name] => Jon Pastor
            [locale] => en_US
            [pic_square] => http://profile.ak.facebook.com/v224/904/100/q780432493_3916.jpg
            [profile_url] => http://www.facebook.com/profile.php?id=780432493
        )

)

PHP:

Array
(
    [0] => Array
        (
            [uid] => 780432493
            [first_name] => Jon
            [last_name] => Pastor
            [name] => Jon Pastor
            [locale] => en_US
            [pic_square] => http://profile.ak.facebook.com/v224/904/100/q780432493_3916.jpg
            [profile_url] => http://www.facebook.com/profile.php?id=780432493
        )

)

Very helpful for debugging to say the least!

$facebook->require_login() has some gotcha behaviors in iframes that are worth mentioning. Hopefully I will save you some time. Over the course of ripping my hair out, I observed one or more of the following on pages with $facebook->require_login() :

  • Facebook generating a new “auth_token” in the url query string each time I requested a page
  • Pages, other than the canvas page, “breaking out” of the Facebook frame
  • Ajax requests that were returing nothing due to a page redirect

All of the above are due to Facebook not being able to maintain authentication across page requests if the page is simply linked to from inside the iframe. Facebook essentially has to re-direct back after generating new authentication credentials.  If you open up your iframe on the canvas page in a new window, you will see the following Get variables in the URL (an example from my page):

fb_sig_in_iframe: 1
fb_sig_locale: en_US
fb_sig_in_new_facebook: 1
fb_sig_time: 1244518218.1479
fb_sig_added: 1
fb_sig_profile_update_time: 1241618728
fb_sig_expires: 1244606400
fb_sig_user: 780432493
fb_sig_session_key: 2.hvRa_GKzi347TYchGAyWXA__.86400.1244606400-780432493
fb_sig_ss: QGgImUePCmQg5dBx_Mm07A__
fb_sig_ext_perms: auto_publish_recent_activity
fb_sig_api_key: 9c74c62f8c7ed2d5fef13719d0256dcb
fb_sig_app_id: 125523728288
fb_sig: 6350aff72d9b7bd40672a8552047b746

These variables in the URL are critical to maintaining authentication across iframe pages. If you reform this query string and append it to your URLs or Ajax requests, then they will be authenticated and all the above errors will go away. Here is som PHP code to do that:

<?
//build the authentication query string

foreach($_GET as $key => $value) {
	if (strpos($key,"fb_sig")!==false) {
		if ($i!=0) $fbvars.= "&";
		$fbvars.= "$key=$value";
		$i++;
	}
}

//then to link, just use $fbvars to add on to the query string of any link

?>
8 Jun, 2009  |  Written by Jon  |  under Facebook Development

I have been vexed over the past week in trying to develop an i-frame based Facebook application with the lack of resources available to answer some simple questions, fix errors, etc. So I will focus my first posts there. You can follow the category/tag for more updates.