small coding-related outlet

coding-related things.

February 14, 2012 at 1:04am

Home

"Connect with Facebook" workflow from Flash/AS3 using only the Facebook PHP API

This tutorial will show you how to let users connect with their Facebook account (i.e. - allow your application to collect their Facebook details such as their name, ID, picture, profile-link and so on…) from within a Flash application, without using any external ActionScript libraries or classes.

Setting up the server-side PHP

Install and setup the Facebook PHP SDK

To gain access to a Facebook user logged-in account, you need to setup a Facebook application. Each user will need to authorize your app (one time only) to allow your app access to his Facebook details.

To setup a new Facebook app, use this interface in the Facebook Developers website.

Once your app is set up, you will have an App ID, and an App Secret both assigned for it automatically by the Facebook app configuration site. Save those for later. You will use those when using the PHP SDK.

The PHP SDK for Facebook can be downloaded from here. To access its functions you need to instantiate a Facebook object, for example:


<?php
  require_once('facebook.php');
  $facebook = new Facebook(array(
      'appId' => 'YOUR_APP_ID',
      'secret' => 'YOUR_APP_SECRET'
  ));
?>

and then you can use its functions, for example:
  $fbID = $facebook->getUser();
which tries to retrieve the Facebook ID of the currently logged-in user.
These steps are also described in the PHP SDK Overview page at Facebook.

We are going to create a PHP page that accomplish the following:
       If a user is logged-in with Facebook and is connected to your app,        return his Facebook ID.
       If not, redirect him through the login and authorization process, then        return his Facebook details.
We’ll call it getfbuser.php:


<?php

require_once 'facebook.php';

$facebook = new Facebook(array( 
    'appId'  => APP_ID,
    'secret' => APP_SECRET,
));

$fbUid = $facebook->getUser();

// We also require a 'doLogin' query parameter to initiate the login redirection.
if (!$fbUid && isset($_GET['doLogin'])) {
  $fb_LoginURL = $facebook->getLoginUrl(array(
   'scope'=>'[..]', // <- You can specify here any additional "extended permissions" 
your app requires. For example the 'publish_stream' permission will allow
your app to publish on the user's wall...
'redirect_uri'=>'postfblogin.php' // This is where the user will be redirected to
after the login to Facebook is finished. We will create this post-login script later.
)); // Redirect the user to the login/authentication process: header('Location: '.$fb_LoginURL); exit(); } else { //If we got his ID - return it. echo $fbUid; exit(); } ?>

Writing the ActionScript in Flash

Have a symbol in your library of a button containing a bitmap of a “Facebook Connect” button, for example like this one: Make sure the “Export for ActionScript" in the Linkage field is set with a class name. We’ll call ours "FBCONNECT”.

We will create a Flash app that displays the user profile picture along with his name that is also a link to his Facebook profile.

First, let’s create a ‘utility function’ that can initiate an asynchronous HTTP POST to a remote URL:


function doHttpPOST (posturl:String,oncompleteFunc:Function) {
	var req:URLRequest = new URLRequest(posturl);
	req.method = URLRequestMethod.POST;
	var reqLoader:URLLoader = new URLLoader();
	reqLoader.addEventListener(Event.COMPLETE,oncompleteFunc);
	reqLoader.load(req);
}

The return value of the POST will be inside the Event parameter of the oncompleteFunc, in event.target.data

Upon startup , we will try to get the user’s Facebook ID by posting to the PHP we created in the first step. If the user is logged-in to Facebook and is connected with your app, the PHP should return his user ID.



// This is where we're gonna store the user's FB details once we have them:
var facebookUser:Object = new Object();


doHttpPOST("getfbuser.php",function(e:Event) 
  {
     // The getUser() function of the PHP SDK returns 0 if it can't get 
an ID - that means the user is not connected, and we show a
"Facebook connect" button:
if (uint(e.target.data) == 0) { var fbConnectBtn = new FBCONNECT(); fbConnectBtn.addEventListener(MouseEvent.CLICK, function(e:MouseEvent) { doFBConnect(); }); addChild(fbConnectBtn); } // If the user is already connected and we have his ID, we can go ahead
and use the 'Graph API' to display his information:
else if (uint(e.target.data) > 0) { facebookUser['id'] = String(e.target.data); getFBInfo(); } });
The getFBInfo function will retrieve the user’s basic details via the Graph API, using the ID we got. If you want to access more extended nonbasic details about the user, you will need to obtain an “access token”, this process is also explained later on. For now, let’s just get those basic details we need:

function getFBInfo() {
    doHttpPOST ("https://graph.facebook.com/"+facebookUser['id'],function(e:Event) {
	   onGetFB(e.target.data);
    });
}

function onGetFB(fbUser:String) {

// The Graph API returns the user details as a JSON string, you can use your
   favorite external ActionScript JSON deserializer, or simply do it "by hand", 
   like in this example:

   var findex = fbUser.indexOf('"name":"')+8;
   facebookUser['name'] = fbUser.substring(findex,fbUser.indexOf('"',findex));
   findex = fbUser.indexOf('"link":"')+8;
   facebookUser['link'] = fbUser.substring(findex,fbUser.indexOf('"',findex)).replace(/\\/g,'');

   //Get the profile picture:
   facebookUser.picture = new Bitmap(new BitmapData(50,50,false,0x000000));
   var picLoader:Loader = new Loader();
   picLoader.contentLoaderInfo.addEventListener(Event.INIT,function(e:Event) {
       facebookUser.picture.bitmapData.draw(picLoader);
       facebookUser.picture.smoothing = true;
       // When we got what we needed - show the user.
       showFBUser();
   });
   picLoader.load(new URLRequest("https://graph.facebook.com/"+facebookUser['id']+"/picture"));
}


The showFBUser function will use the obtained information and display it:

function showFBUser() {
    var userSpr:Sprite = new Sprite();
    var userNameText:TextField = new TextField();
    userNameText.defaultTextFormat = new TextFormat
    ('Arial',18,0x0000cf,true,false);
    userNameText.width = 200;
    userNameText.x = 54; userNameText.y = 2;
    userNameText.htmlText = "<a href='"+facebookUser['link']+"'>"
    +facebookUser['name']+"</a>";
    userSpr.addChild(facebookUser.picture);
    userSpr.addChild(userNameText);
    addChild (userSpr);
}

Here is an example for a sample result display:

The name will be a clickable hyperlink that opens a new browser-window with the user’s Facebook profile in it.

Handling a new user login/connection

As you recall when we first do a POST to the php to get the user’s id, one of the options is that the user is not connected to your app and/or not logged-in to Facebook. In that case, we displayed a “Connect with Facebook” button. We will deal with that button’s functionality next (of-course you could also simply trigger that functionality automatically instead of putting the button, but there will be a difference - see below after the code block):

function doFBConnect() {
    ExternalInterface.call("FBWin = window.open",'http://url/getfbuser.php?doLogin',
    '_blank',"width=1016,height=624,location=no,menubar=no");
}

What this will do is run a little bit of Javascript code that will open a new window where the user can do the login (this is handled by the php code we wrote earlier, that uses the getLoginUrl function from the Facebook PHP SDK). We also save a reference for the window (‘FBWin’) so we could later close it automatically once we no longer need it.

[Note about not using a button and instead just opening the window: most browsers have a “pop-up blocker” that only allows code that opens a new window to run if it was initiated by a user (like clicking on a button). I’m pretty sure that if you won’t use a button - the new popup window will be blocked and the user will have to allow it first…]

If the user is not logged-in to Facebook - he will be presented with Facebook’s login screen on the pop-up window. If the user never used your APP before, he will be presented with Facebook’s “app authorization” screen. In any case, after that, there should be a redirection to the url we specified in the ‘redirect_uri' parameter we specified back in the PHP. We wrote the redirect to be to a file called 'postfblogin.php’.

Handling post-login / User Authorization

The redirection occurs with added querystring parameters that Facebook adds to the url. If there was any error during the login-process the parameter ‘error' will be added.
If the login was ok - a ‘code' parameter is added to the url.

The next step is to use this “code” to obtain an “access token”. This access token can then be used to get information about the currently logged in user, by using the Graph API “/me" connection.
(An access token can also be used to query other non-public parts of the Graph API).

To obtain an access token you use the URL: “https://graph.facebook.com/oauth/access_token"
This URL needs to accept four parameters:

  • code: The ‘code' we got in the 'code' parameter in this stage.
  • client_id: Your FB app ID.
  • client_secret: Your FB app Secret.
  • redirect_uri: *must* be the same as the previous “redirect_uri” parameter that got us here.

[For more information relating to this, you can also read the document on “Authentication” at Facebook.]

So, the PHP code for the ‘postfblogin.php’:

// Handle errors:
if (isset($_GET['error'])) {echo 'ERROR'; die(); }
// If ok: 
if (isset($_GET['code'])) {
   $thecode = $_GET['code']; 
   $redirectURI = "postfblogin.php";
   $getaccessURL = 
           'https://graph.facebook.com/oauth/access_token?'.
           'client_id='FB_APP_ID&' . 
           'client_secret=''FB_APP_SECRET&' . 
           'code=' . $thecode . '&redirect_uri=' . $redirectURI;

   // If it works you should get back an access token, 
      and an "expiry date" parameter. 

   $accessResponse = @file_get_contents($getaccessURL);
   $accessData = null;
  // Seperate the token from the expiry parameter: 
   parse_str($accessResponse,$accessData);

   // Now, using the access token, we can access the Graph API '/me':
   $userDetails = json_decode(file_get_contents(
   "https://graph.facebook.com/me?access_token=" . 
   $accessData['access_token']));
}


Callbacking the ActionScript / Back to the Flash

We now have the information we wanted about the Facebook user. We need to send it back to our Flash app somehow, and arise a callback function. To do that, we can use the LocalConnection ActionScript class.

Back in our Flash program, we add:


var localCon:LocalConnection = new LocalConnection();

 // You can give any string as the "connect" parameter, 
    but it must be identical in the "other side". 
    We're gonna write the "other side" after this part...
localCon.connect("facebookConnect");
localCon.client = this;

// Define a callback to accept the collected information:
function onFBConnectBack(fbParams:Object) {
    // Close the pop-up window we opened earlier for the login, 
       using Javascript and the window reference we saved when we opened it.
    ExternalInterface.call("FBWin.close");
    // The fbParams parameter should be an object with everything we need, 
       so just assign it to our other object:
    facebookUser = fbParams;
    //Get Profile picture from the Graph API:
    facebookUser.picture = new Bitmap(new BitmapData(50,50,false,0x000000));
    var picLoader:Loader = new Loader();
    picLoader.contentLoaderInfo.addEventListener(Event.INIT,function(e:Event) {
       facebookUser.picture.bitmapData.draw(PicLoader);
       facebookUser.picture.smoothing = true;
    });
    picLoader.load(new URLRequest("https://graph.facebook.com/"
    +facebookUser['id']+"/picture"));
    // The 'Facebook connect' button is no longer required:
    removeChild(fbConnectBtn);
    // The object is filled with the information. Display it: 
    showFBUser();
}


Trigger the callback from the PHP

We now need to create an additional SWF file, containing very short code to send back the information to our original Flash object and trigger the callback function. Let’s call it ‘fbconnect.swf’. The code for this flash:

// stage.loaderInfo.parameters is an object that automatically gets 
   assigned with all the variables in the flashVars parameters of  a 
   flash object. We're going to use that for our advantage: 
var fbParams:Object = 
 stage.loaderInfo.parameters;

var localCon:LocalConnection = new LocalConnection();
// for the 'send' method - the first parameter is the "connection string", 
   the second is the name of a function defined on the other side, 
   and the third is any additional parameters for that function
localCon.send("facebookConnect", "onFBConnectBack",fbParams);

What’s left is to embed the sending Flash object into the post-login PHP. Extend the if-block, and add:


// At this point $userDetails is an array with keys->values of 
   information about the user. We need to turn it into a "querystring" 
   format, as we're gonna use 'flashVars' to pass it. 
   Let's just put the things we need:

$userDetailsVarStr = "id=" .   $userDetails->id .'&' .
                     "name=" . $userDetails->name . '&' .
                     "link=" . $userDetails->link;

  // Now simply embed the 'fbconnect' flash into the page, and give it
     the relevant flashVars: 
   echo '<embed src="fbconnect.swf" width="0" height="0" hidden="true" 
          flashVars="'.$userDetailsVarStr.'" />';


…and this will trigger the onFBConnectBack function back in the original Flash, giving it the information we need (and it’ll also take care of closing the popup window…) and that’s it!

Notes

  1. icodethings posted this