The User Experience is a very important element of system design. At HitSend Inc., we really try to make that experience easy and intuitive for our users.
With this in mind, we knew our users would need to have user profiles to access our system. However, we did not want to force them to create another username and password to remember. So from the beginning we knew we wanted to capitalize on the robust authentication systems already created!
This tutorial will show how we use the new Facebook Connect Graph API to supplement our authentication system using the CodeIgniter PHP framework.
First, I want to thank Elliot Haughin for his work in creating a Facebook Connect CodeIgniter framework that helped get ours up and running fairly quickly. (Actually, it is because of his that I have decided to release this to the wild, in the hopes that someone comes along and makes an even better one that I can use!).
To make this tutorial as simple as possible, I’ve assume that you have basic knowledge of the CodeIgniter framework and have looked into the Facebook API documentation (… at least a little bit…)

Alright, let’s get down to business!
This tutorial is split into a few parts:
The first thing you need to do is create a Facebook application. There are tons of tutorials out there for doing this, so I won’t belabour this section. Facebook have a pretty decent walk through for creating an app here. Once you have created your app, make note of the api key, secret key and the site url. We will be using these later on in the tutorial.
Here is an image of what my application settings look like:
The Site URL is the root location of your site, and the Site Domain is (as you would think) the domain of your site. When setting up the application using the app id and secret key from a domain different from one you specified in the Site Domain field will cause an error. So make sure this part is set up right before you continue.
Moving on…
Again, for simplicity sake, here is what our user table looks like. In a real system we would capture a lot more information than this.
CREATE TABLE user ( user_id VARCHAR(100), full_name VARCHAR(100), pwd VARCHAR(100), fb_uid VARCHAR(100), );
The fields are pretty self explanatory. The ‘user_id’ is what the user would log in as. The ‘pwd’ field is the user’s password (ideally encrypted, to keep the data secure), the ‘full_name’ is just another field you can capture. You can add more fields to this table like, email address, birthday, or whatever else you want to capture in your system.
The ‘fb_uid’ field will be the user’s Facebook account id that will be populated through Facebook, and is how we authenticate a person into our system through Facebook.
The facebook configuration is used to store the users api key and secret key.
You will also need to create a file ‘facebook.php‘ in the ‘application/config/‘ folder. It only contains the following 3 lines:
<?php $config['facebook_api_key'] = 'your_facebook_api_key'; $config['facebook_secret_key'] = 'your_facebook_secret_key';
Creating a CodeIgniter library is the simplest way to integrate the Facebook Graph API into our system.
Download the latest PHP Facebook API from http://github.com/facebook/php-sdk/ . All you really need from here is the facebook.php file.
Create a new directory called ‘facebook‘ under ‘application/libraries/’ and place this facebook.php file here.
Now create a PHP file called ‘fb_connect.php‘ in the ‘application/libraries/‘.
Below is the code for this PHP file: (it is pretty simple, although it might be easier to read through the sample code.)
<?php
//fb_connect.php
//Author: Graham McCarthy, HitSend Inc., September 29th, 2010
//Email: graham@hitsend.ca
//Description: facebook connect library, connects to facebook and
// stores all the required information in return variables
//grab the facebook api php file
include(APPPATH.'libraries/facebook/facebook.php');
class Fb_connect {
//declare variables
private $_obj;
private $_api_key = NULL;
private $_secret_key = NULL;
public $user = NULL;
public $user_id = FALSE;
public $fbLoginURL = "";
public $fbLogoutURL = "";
public $fb = FALSE;
public $fbSession = FALSE;
public $appkey = 0;
//constructor method.
function Fb_connect()
{
//Using the CodeIgniter object, rather than creating a copy of it
$this->_obj =& get_instance();
//loading the config paramters for facebook (where we stored our Facebook API and SECRET keys
$this->_obj->load->config('facebook');
//make sure the session library is initiated. may have already done this in another method.
$this->_obj->load->library('session');
//
$this->_api_key = $this->_obj->config->item('facebook_api_key');
$this->_secret_key = $this->_obj->config->item('facebook_secret_key');
$this->appkey = $this->_api_key;
//connect to facebook
$this->fb = new Facebook(array(
'appId' => $this->_api_key,
'secret' => $this->_secret_key,
'cookie' => true,
));
//store the return session from facebook
$this->fbSession = $this->fb->getSession();
$me = null;
// If a valid fbSession is returned, try to get the user information contained within.
if ($this->fbSession) {
try {
//get information from the fb object
$uid = $this->fb->getUser();
$me = $this->fb->api('/me');
$this->user = $me;
$this->user_id = $uid;
} catch (FacebookApiException $e) {
error_log($e);
}
}
// login or logout url will be needed depending on current user state.
//(if using the javascript api as well, you may not need these.)
if ($me) {
$this->fbLogoutURL = $this->fb->getLogoutUrl();
} else {
$this->fbLoginURL = $this->fb->getLoginUrl();
}
} //end Fb_connect() function
} // end class
The reason for creating the library ‘fb_connect’ is that whenever we want to access the facebook api, all we need to do in our controller is load the library:
$this->load->library('fb_connect');
Then in our controller code we can make calls like:
$this->fb_connect->user_id; // returns the logged in users id $this->fb_connect->user; // returns an object containing all the user data.
You can also check if you have a valid and authenticated facebook session like this:
if($this->fb_connect->fbSession) {
// logged in just fine
} else {
//Not Logged in
}
The Login Controller and view can get a little messy. I’ll assume you’ve already created a login that validates by using the user_id and pwd. Again, there are plenty of tutorials around that cover this sort of interaction. NetTuts have a very easy to follow tutorial.
Logging in through Facebook skips this process.
It compares the item returned by $this->fb_connect->user_id to the fb_uid field in the user table.
Here is what a sample login.php controller looks like:
<?php
class Login extends Controller {
function Login() {
parent::Controller();
$this->load->model('user_model');
}
function index() {
//create blank data array to return
$data = array();
$this->load->library('fb_connect');
$data = array(
'facebook' => $this->fb_connect->fb,
'fbSession' => $this->fb_connect->fbSession,
'user' => $this->fb_connect->user,
'uid' => $this->fb_connect->user_id,
'fbLogoutURL' => $this->fb_connect->fbLogoutURL,
'fbLoginURL' => $this->fb_connect->fbLoginURL,
'base_url' => site_url('login/facebook'),
'appkey' => $this->fb_connect->appkey,
);
$this->load->view('login_view', $data);
}
//This won't destroy your facebook session
function logout() {
$this->session->sess_destroy();
$data['logged_out'] = TRUE;
//$this->index($data);
redirect('/login/index');
} // function logout()
function _facebook_validate($uid = 0) {
//this query basically sees if the users facebook user id is associated with a user.
$bQry = $this->user_model->validate_user_facebook($uid);
if($bQry) { // if the user's credentials validated...
$data = array(
'user_id' => $uid,
'is_logged_in' => true,
'list_type' => 'hot'
);
$this->session->set_userdata($data);
$uri_var = $this->uri->segment(3);
if (strlen($uri_var) > 0 ){
$url_location = $uri_var;
$url_location = str_replace('-', '/', $url_location);
redirect($url_location);
} else{
redirect('/message/index');
}
} else {
// incorrect username or password
$data = array();
$data["login_failed"] = TRUE;
$this->index($data);
}
}
function facebook() {
//1. Check to see if the facebook session has been declared
$this->load->library('fb_connect');
if(!$this->fb_connect->fbSession) {
//2. If No, bounce back to login
$this->index();
} else {
$fb_uid = $this->fb_connect->user_id;
$fb_usr = $this->fb_connect->user;
if($fb_uid != false) {
//3. If yes, see if the facebook id is associated with any existing account
$usr = $this->user_model->get_user_by_fb_uid($fb_uid);
if( is_array($usr) && count($usr) == 1) {
$usr = $usr[0];
//3.a. if yes, log the person in
//echo "Logging in via facebook...";
$this->_facebook_validate($usr->user_id);
} else {
//3.b. if no, register the new user.
//echo "Creating a new account...";
//search for missing data and notify the user of what is missing.
$fname = $fb_usr["first_name"];
$lname = $fb_usr["last_name"];
$fullname = $fb_usr["name"];
$pwd = ''; //left blank so user can modify this later
$email = $fb_usr["email"];
//$fb_uid = already defined.
$db_values = array (
'user_id' => "fb:".$fb_uid,
'fb_uid' => "fb:".$fb_uid,
'full_name' => $fullname,
'pwd' => "",
);
//data ready, try to create the new user
if($query = $this->user_model->create_user($db_values) ) {
$data['account_created'] = true;
//log user in
$this->_facebook_validate($db_values["user_id"]);
} else {
//Did not work, go back to login page
$this->index();
}
}
}
}
}
}
This controller includes a model called ‘user_model.php‘. Here is the code for that model:
<?php
class User_model extends Model {
var $user_id = "";
var $full_name = "";
var $pwd = "";
var $fb_uid = "";
function User_model() {
//Call the Model constructor
parent::Model();
}
function validate_user_facebook($uid = 0) {
//confirm that facebook session data is still valid and matches
$this->load->library('fb_connect');
//see if the facebook session is valid and the user id in the sesison is equal to the user_id you want to validate
$session_uid = 'fb:' . $this->fb_connect->fbSession['uid'];
if(!$this->fb_connect->fbSession || $session_uid != $uid ) {
return false;
}
//Receive Data
$this->user_id = $uid;
//See if User exists
$this->db->where('user_id', $this->user_id);
$q = $this->db->get('users');
if($q->num_rows == 1) {
//yes, a user exists,
return true;
}
//no user exists
return false;
}
function create_user($db_values = '') {
$this->user_id = $db_values["user_id"];
$this->full_name = $db_values["full_name"];
$this->pwd = md5($db_values["pwd"]);
if(strlen($db_values['fb_uid']) > 0) {
$this->fb_uid = $db_values['fb_uid'];
} else {
$this->fb_uid = "";
}
$new_user_data = array(
'user_id' => $this->user_id,
'full_name' => $this->full_name,
'pwd' => $this->pwd,
'fb_uid' => $this->fb_uid,
);
$insert = $this->db->insert('users', $new_user_data);
return $insert;
}
function get_user_by_fb_uid($fb_uid = 0) {
//returns the facebook user as an array.
$sql = " SELECT * FROM SV_users WHERE 0 = 0 AND fb_uid = ?";
$usr_qry = $this->db->query($sql, array('fb:'.$fb_uid));
if($usr_qry->num_rows == 1) {
//yes, a user exists
return $usr_qry->result();
} else {
// no user exists
return false;
}
}
}
The login.php controller links to a view called login_view.php. Here is what it looks like:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" xmlns:fb="http://www.facebook.com/2008/fbml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>SoapBox Login</title>
</head>
<body>
<!-- FB CODE -->
<div id="fb-root"></div>
<script type="text/javascript">
window.fbAsyncInit = function() {
FB.init({appId: '<?=$appkey?>', status: true, cookie: true, xfbml: true});
/* All the events registered */
FB.Event.subscribe('auth.login', function(response) {
// do something with response
login();
});
FB.Event.subscribe('auth.logout', function(response) {
// do something with response
logout();
});
};
(function() {
var e = document.createElement('script');
e.type = 'text/javascript';
e.src = document.location.protocol + '//connect.facebook.net/en_US/all.js';
e.async = true;
document.getElementById('fb-root').appendChild(e);
}());
function login(){
document.location.href = "<?=$base_url?>";
}
function logout(){
document.location.href = "<?=$base_url?>";
}
</script>
<!-- END OF FB CODE -->
<form action="<?php echo site_url('login/validate_user/') . '/' . $uri_var;?>" method="post">
<p>username:<br /><?= form_input('user_id', '') ?></p>
<p>password:<br /><?= form_password('pwd', '') ?></p>
<p id="buttons">
<fb:login-button onlogin="login();" size="medium" perms="email,offline_access,user_birthday,status_update,publish_stream">Connect</fb:login-button>
<?= form_submit('submit', 'Login') ?>
</p>
</form>
</body>
</html>
It might be a little tricky copy and pasting the code in this tutorial. So feel free to download the sample source. It is fairly documented, and should show you how to integrate a login system with Facebook
If you have any questions or problems, or if you have a better way to integrate Facebook authentication in your system, please leave a comment!
Cheers,
Graham McCarthy. HitSend Inc.