Monthly Archives: January 2010

Use Facebook Connect in your application

Recently I’ve got to enable one site of mine with this “Facebook Connect” thingy, my primary goal being the increase of the conversion rate, in the way that people could use their Facebook account to log into my web site without a need for a boring registration process. Just click two buttons, and you’re in. If a person had a site account already, I’ll give him the opportunity to merge her Facebook account with the old one. Eventually, upon a succesfull “connect” round, a new account would be created within my application. It’s a cute www: a web win-win.

That is all what I needed, from Facebook: I do not need any fancy “get your friends here” or “post in your wall” rubbish. Simple and plain “single sign on”, among Facebook and my application.

After a quick search, the tutorials I found here and there were very disappointing (just a point of view, no offense), with a lot of useless PHP code. So I give you just one more tutorial that focuses more on the process than in the copy & paste kind of help.

I will use PHP for some examples, and FB for “Facebook” so bear with me and give it a spin.

What you need:

  • a FB account, if you don’t own one already. Unlikely; I’ll skip this step :)
  • a new FB application need to be created
  • the FB PHP library, to easily talk to their RESTful API
  • Some code refactoring of your own

Creating a new FB application.

Two paths, here:

Note that, whichever way you’ll choose, you will end up creating the exact same thing: an FB application (all your applications are stored here).

We’ll use the wizard:

  • the website name is just the name of the application (the handle by which you’ll refer to it in the application list).
  • the website url is self explanatory. Note that you could use ANY kind of URL, even something like “http://myapplication.localdomain”. In fact, FB will not need to contact the site, so you can use an development URL as well. For the test purposes I created two applications: one for the “real thing” and one for the mydomain.local devel environment.

The next step will ask you to download a file. You can put the file WHEREVER you want. The root directory of your site is the first choice, and it’s where the wizard will try to find it. There’s no need for the wizard to find the file, though: it’s only a test. You can download the file and skip the test pressing “Upload later“. Two words about that particular file: the file is part of the system that permits our application to be proxied to FB (and vice-versa). I will not enter in details here, but think about this file as your “gateway” to and from the FB requests (more info). The other thing is: there is NOTHING in that file that identifies you application. Every FB application of the world could use the same xd_receiver.htm file. The file name itself is not important… it’s just the default. More on this later.

The third step is the landing page for your newly created FB application. Just a comfy place to pick things up. You need to write down the API KEY and the SECRET strings. You’ll use them from within your application.

What you also need to take from this page is the JavaScript snippet at point 1) and the FBML markup for the “Connect with Facebook” button at point 2).

Enough for the FB setup.

The FB PHP Library and the FB API

This is a set of helper PHP classes that will give you a simple PHP API interface to the RESTful FB API. You could even NOT use the library, and talk directly to the REST endpoints with some code of your own. Your choice.
The FB API are documented here, while you can download the latest version of the PHP 5 Library via SVN

svn co http://svn.facebook.com/svnroot/platform/clients/php/trunk/ fb

(more info on FB Client libraries)

We are finally ready to get our hands dirty.

Hands on the code

We first need to focus on how things works, at an higher level. What will happen when a not logged-in user will click the “Connect with Facebook” button? Using some sort of magic Facebook will test if the user is currently logged in Facebook. If it’s not, it will spawn a popup window asking two things: the user has to agree to give your application access to her data, and after that Facebook will ask her for credential (username/password, as usual). Upon a succesful login, FB will redirect the user to your application toward an url of your choice (let’s call it the “FB Connect endpoint“).
If the user is already logged in Facebook and has already given permission to our application to read some of her data, the login process will be completely transparent. The user clicks on our FB blue-ish button, and he will be instantly logged in our application too. Oh, joy.

As for the HTML part, you will place the FBML markup for the login button you got beforehand wherever you want. The FBML have to be programmatically converted in HTML by JavaScript, and for that to work you need to include the JavaScript snippet you already have. Put it at the end of your <body>, for example, and then run the FB.init() function. This function will be passed two parameters: the API KEY and the name and location of the “gateway” file. As said before, if the second parameter is not passed, the default is “xd_receiver.htm” on the document root.

  <!-- The login button, somewhere in your page -->
  <fb:login-button onlogin="window.location='/fbconnect.php';" v="2" size="medium">Login with Facebook</fb:login-button>
  ...
  <!-- At the page end of the page, presumibly -->
  <script src="http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php/en_US"></script>
  <script>
    FB.init("b4bbr43b4bb3b3b3");
  </script>
</body>
</html>

The interesting part, here, is in the highlighted row. The onlogin attribute contains what we pretentiously called the “FB Connect endpoint”. The onlogin attribute value is a JavaScript snippet that will be automatically run after a succesfull FB login. What we say here is: after a login, please redirect the user to our “fbconnect.php” page.
The fbconnect.php page is where OUR magic will happen. There, we will use the FB Client API to ask FB some questions: “Is this guy a Facebook, logged in user?”, “Can you please give me the picture of him?”… and so on.
The code, here, is given only as an example; think about it more as a pseudocode, really. The actual code I use is somewhat more complex, and I needed to dumb it down a little for clarity.

require("fb/facebook.php");
$fb = new Facebook("b4bbr43b4bb3b3b3", "supersecret1234");
/* If it's present, ask FB for the ID of the current user */
$fbId = $fb->get_loggedin_user();
if (empty($fbId)) {
  /* No FB user, redirect to home page */
  header("Location: /");
}
/* Now we know the FB user id.
   It's our responsability to ask our Database if we already know him */

You need to have a way to find one user of yours given its FB user id. For instance I used a “fb_id” column in my Users table.

What happens now is up to you. There will presumably be two major cases:

  1. the user already exists: I programmatically login him into my application, and redirect to the home page as a logged in user.
  2. the user does not exist: I give her the choice to merge her old account or to create a new one

For the merge part, I need him to login with his credentials and then update the Users table with his FB id.

For the registration part, I luckily do not need anything else that FB can’t give me; so it’s a matter of pushing a button. The code is something like that:

$fbInfo = $fb->api_client->users_getInfo($fbId, array('name', 'pic_square', 'proxied_email'));
$model = new User();
$name = $fbInfo['name'];
$tries=1;
# find a unique username
do {
  $user = $model->fetchRow($model->select()->where('username=?', $name));
  if (!$user)
    break;
  else
    $name = $name . ($tries++);
} while(TRUE);
$user = $model->createRow();
$user->username = $name;
$user->avatar = $fbInfo['pic_square'];
$user->name = $fbInfo['name'];
$user->fb_proxy_email = $fbInfo['proxied_email'];
$user->fb_id = $fbId;
...
$user->save();
...

Finally, let me complain a bit: I find writing code that interacts with Facebook a very frustrating experience. The information you need is scattered all over the web (and the Facebook site itself, even), and examples quality is very poor. The technology behing FB is very sophisticated, though, and no matter what they try to do, you need to grasp some concepts that are sometimes quite difficult to master or a nightmare to debug.

Good luck.

Further readings


jQuery vs document.getElementById

With the first post of the year, I’d like to present the results of a (very) simple and unreliable performance benchmark.

The question I would like to give an answer to was: giving the selector of an HTML ID, how much the document.getElementById is faster than the jQuery selection? Well – as it tourned out – it is astonishingly faster.

The test run over 100000 calls to the same minimal function and then collect the result in millisecond. For each test, 8 runs were made and the greatest and lowest value were dropped before the average time was computed. Every test was ran against Firefox 3.5.6, Firefox 3.6b5, Chrome 4, Safari 4, IE 8 and Opera 10.10.

“Why don’t run the test also against the soon to be released jQuery 1.4.0?”, I asked myself. So I did.

The test code itself goes along these lines:

function benchmark(f, result) {
  var start = new Date();
  f();
  var stop = new Date();
  document.getElementById(result).innerHTML = stop - start;
}

$("#start").click(function() {
    benchmark(function() {
      var e;
      for(n=0; n < 100000; n++) {
        e = $('#testID');
// or  e = document.getElementById('#testID');
      }
    }, "result");
    return false;
});

And here comes the whole picture:

What did I learn?

  • when possible, use the document.getElementById() native function (or a simple helper wrapper) instead of the jQuery method
  • IE and Firefox 3.5 are embarassingly slow
  • Chrome and Safari are embarassingly fast
  • Firefox 3.6 is gaining a lot of performance points, but still…
  • Opera 10.10 is good, but the gEBI performances are very bad
  • Chrome is loosing something with jQuery 1.4. Well, it seems so. I don’t think this is real.
  • The best performance gain with jQuery 1.4 would be for IE8

Remember that this test is extremely unreliable and of indicative quality only. Do not take any assumption for granted :)

ADDENDUM: as a follow up to a discussion on Friendfeed, I ran one more test. This time I’ve used a wrapper like this one:


function $getId(id) {
  $(document.getElementById(id));
}

$("#startWRAPPER").click(function() {
    benchmark(function() {
      var e;
      for(n=0; n < 100000; n++) {
        e = $getId('testID');
      }
    }, "result");
    return false;
});

When you need an ID, as a jQuery object, using the wrapper can certainly give you same benefits. The test has been ran with the latest jQuery 1.4 version.


I contenuti di questo sito sono distribuiti con una licenza Creative Commons 2.5 eccetto dove diversamente specificato.

Tema WordPress Punto5 sviluppato da Claudio Cicali; icone del set famfamfam silk e komodomedia.

© 2005-2010
Claudio Cicali