How to make a basic “Login via Facebook” with PHP & JavaScript

You’ve seen how some popular websites let you register or login via Facebook — Pinterest, Vimeo, Lifehacker, and many more.

In this blog post, I’ll show you the very basic setup of the Facebook login button for your website. It is up to you to enhance the functions of your registration system.

Note: There are periodic updates to the Facebook API, sometimes resulting to issues with previously working implementations of the API. So please note that this tutorial was written in the third week August 2015. πŸ™‚

I began writing this tutorial late in August, but because of other projects, was able to publish it when it’s already September.

This Facebook login tutorial’s coverage and limitations

  • This Facebook login tutorial will cover only the basic setup of the “Login via Facebook” button.
  • Extended permissions request and the setup on your server will not be included for now.

Requirements of this tutorial to integrate Facebook login to your website

  • Internet connection
  • JavaScript turned on in your web browser
  • Basic knowledge in HTML, PHP, and JavaScript
  • A Facebook Developer account – find out how to create one here
  • Apache and PHP on local machine (e.g. in XAMPP)

My coding environment for this tutorial

I’ll run the codes in XAMPP on Windows 7.


And now, let’s begin with the Facebook login integration tutorial!

There will be previews of codes from here on, and near the end of the page will be a download link so you could get a copy of my Login via Facebook codes.

I will not explain the codes line by line anymore, but I already placed comments on most lines on the code previews.

Part 1: Prepare a Facebook app

Go to the Facebook Developers site.

facebook-login-tutorial-add-new-app

Under the “My Apps” menu item, choose “Add a New App”.

facebook-login-tutorial-add-new-app-website

Choose “Website”.

facebook-login-tutorial-add-new-app-name

We are about to create a Facebook app ID.

Type a name for your Facebook app. I’m naming mine “My App August 2015” for this tutorial.

facebook-login-tutorial-add-new-app-id-1

Leave the toggle for “Is this a test version of another app?” to know, and choose any category that fits the type of website you’r going to use the Facebook login with. I’m going to choose “Reference” for this tutorial.

Let’s setup our site later locally. I plan to put my codes later in a directory named “fb_login_tut_aug2015” in my XAMPP htdocs folder.

facebook-login-tutorial-add-new-app-site-url

First, you may want to take note of the JavaScript code snippet provided in the “Setup the Facebook SDK for JavaScript” page (see photo above). You’ll need it for the site later. The “app ID” is included in the fbAsyncInit as “appId”.

Enter the URL of our localhost site: http://localhost/fb_login_tut_aug2015. You can use any folder name you want, but remember that I’ll refer to the local directory as “fb_login_tut_aug2015” from here on.

Part 2: Setup the site in localhost

Database table schema

Create the `users` table using this schema:

CREATE TABLE IF NOT EXISTS `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `fb_app_user_id` varchar(255) DEFAULT NULL,
  `name` varchar(255) DEFAULT NULL,
  `email` varchar(255) DEFAULT NULL,
  `picture_url` longtext NOT NULL,
  `created_at` datetime NOT NULL,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `fb_app_user_id` (`fb_app_user_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1;
Folder structure:
fb_login_tut_aug2015
β”‚   index.php
β”‚   login.php
β”‚   includes.php
β”‚   controllers.php
└───classes
β”‚   β”‚   Account.class.php
β”‚   β”‚   MysqliDb.class.php
└───assets
    β”œβ”€β”€β”€css
    β”‚   β”‚   style.css
    β”œβ”€β”€β”€images
    β”‚   β”‚   loading.gif
    β”œβ”€β”€β”€js
    β”‚   β”‚   login.js
index.php for Login via Facebook

Create a file, index.php, and save it under the directory fb_login_tut_aug2015.

The index will be the page shown to the user when logged in. Picture, name and email address as saved on the user’s Facebook account, if available, are shown on the index page.

Place the following code into that file:

<?php

/**
 * Include session start, class inclusions, and database config
 */

require_once('includes.php');

/**
 * If not logged in, take user to login page
 */

if(!isset($_SESSION['logged_user_id']) || strlen($_SESSION['logged_user_id']) < 1 ) {
	header("Location: login.php");	
} 

/**
 * Fetch user data for profile display
 */

$account = new Account;
$user = $account->get_user_data($_SESSION['logged_user_id']);

?>

<!DOCTYPE html>
<head>
	<title>Login via Facebook from blog.catzie.net</title>
	<link rel="stylesheet" href="assets/css/style.css">
</head>
<body>

    <h1>Welcome!</h1>

	<div id="profile">

		<h2>Your Profile</h2>

		<div class="profile-picture_url">
			<img src="https://graph.facebook.com/<?php echo isset($user['fb_app_user_id']) ? $user['fb_app_user_id'] : '' ; ?>/picture?type=large" alt="" width="200" height="200">
		</div>
		<div class="profile-name">
			<span class="label">Name:</span>
			<?php echo (isset($user['name']) && strlen($user['name']) > 0 ) ? $user['name'] : 'n/a' ;?>
		</div>
		<div class="profile-email">
			<span class="label">Email:</span>
			<?php echo (isset($user['email'])  && strlen($user['email']) > 0 ) ? $user['email'] : 'n/a' ;?>
		</div>
		<div class="profile-created_at">
			<span class="label">Registration Date:</span>
			<?php echo (isset($user['created_at']) && strlen($user['created_at']) > 0 ) ? $user['created_at'] : 'n/a' ;?>
		</div>

		<p><a href="controllers.php?p=logout">Logout</a></p>

	</div>    
</body>
</html>



login.php for Login via Facebook

When index.php detects that the user is not logged in, he or she is redirected to the login.php page.

The login page is where the “Login via Facebook” button is placed. The user authorizes the Facebook app here to retrieve user data, before being able to finally log in.

<?php

if(session_id() == '') {
    session_start();
}

?>

<html>
<head>
	<title>Login via Facebook from blog.catzie.net</title>
	<link rel="stylesheet" href="assets/css/style.css">
	<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
	<script src="assets/js/login.js"></script>
</head>
<body>
	<h2>Login</h2>
	<button type="button" onclick="fb_login()">Login via Facebook</button> 
	<img src="assets/images/loading.gif" alt="loading..." id="loading_gif" style="visibility:hidden">


	<div id="messages">
		<div class="message auth-failed error" style="display:none">
			Sorry, something went wrong with your Facebook login attempt.
		</div>
		<div class="message success" style="display:none">
			Logging you in...
		</div>
	</div>

	<div id="footer">
		<small>
			Sample "Login via Facebook" from <a href="http://blog.catzie.net" target="_blank">blog.catzie.net</a>
		</small>
	</div>
</body>
</html>



includes.php for Login via Facebook

When at least two of my PHP files call for the same functions or require the same group of files, I think it’s practical to just embed those common codes. I placed my common codes in includes.php:

≪?php

/**
 * Start session for login system
 */

if(session_id() == '') {
    session_start();
}

/**
 * Include classes
 */

require_once('classes/Account.class.php');
require_once('classes/MysqliDb.class.php');

/**
 * Database Config and instantiation
 */

$db_config = array(
	'host' => 'localhost', 
	'username' => 'root', 
	'password' => '', 
	'databaseName' => 'fb_login_tut_aug2015'
);


$mysqli = new MysqliDb ($db_config['host'], $db_config['username'], $db_config['password'], $db_config['databaseName']);
controllers.php for Login via Facebook

I made controllers.php so I could place functions that will possibly be called from different places. It will be good to place functions that interact with classes/models and views.

check_fb_data() is called through Ajax from the login page, and then it calls the Accounts class to check for data in our “users” table.

<?php

/**
 * Include session start, class inclusions, and database config
 */

require_once('includes.php');


/**
 * Controller for page routes
 * Add more switch cases and functions as needed
 */

if(isset($_GET['p'])){
	$p = $_GET['p'];
	$return = array();

	switch($p){
		case "check_fb_data": check_fb_data(); break;
		case "logout": logout(); break;
	}
}


/**
 * Save FB data (attempt)
 * return { "success" : boolean, "message" : string }
 */
function check_fb_data(){
	$fb_data = $_POST;

	$fb_data['fb_app_user_id'] = (isset($fb_data['fb_app_user_id'])) ? $fb_data['fb_app_user_id'] : "";
	$fb_data['name'] = (isset($fb_data['name'])) ? $fb_data['name'] : "";
	$fb_data['email'] = (isset($fb_data['email'])) ? $fb_data['email'] : "";
	$fb_data['picture_url'] = (isset($fb_data['picture_url'])) ? $fb_data['picture_url'] : "";

	/**
	 * Check existence of user in database
	 */
	
	$account = new Account;
	$user_db_id = $account->get_user_db_id($fb_data['fb_app_user_id']);

	/**
	 * If the Facebook app user ID is not in the database
	 */

	if(false === $user_db_id){
		$user_db_id = $account->add_user($fb_data['fb_app_user_id'], $fb_data['name'], $fb_data['email'], $fb_data['picture_url']);
		$return['success'] = true;
		$return['message'] = "Registration successful!";
	} 

	/**
	 * If the Facebook app user ID is already in the database
	 */
	
	else { 
		$return['success'] = true;
		$return['message'] = "Welcome back!";
	}

	/**
	 * Log the user in by setting the session
	 */

	$_SESSION['logged_user_id'] = $user_db_id;

	/**
	 * Return JSON to the Ajax call
	 */

	echo  json_encode($return);
	exit;
} 

/**
 * Logout
 * Destroy session and redirect user
 */

function logout(){
	session_destroy();
	header("Location: index.php");	
}


Account.class.php for Login via Facebook

I wrote this Account class, separating the database interactions from the rest of the code, with goal of making the functions in the class reusable.

<?php

/**
 * The Account class saves and retrieves data
 * to and from the `users` table. Coded in August 2015.
 *
 * @author    Catzie    <i@catzie.net>
 */

class Account{
	
	protected $db;

	function __construct(){

		/**
		 * $mysqli was instantiated in includes.php
		 * Now, we assign it to the property $this->db
		 */
		
		global $mysqli;
		$this->db = $mysqli;
	}

	/**
	 * Get database row ID of user
	 * @param    string        $fb_app_user_id    ID of user in the Facebook app
	 * @return   int|boolean   Database row ID if existing, 
	 *                         otherwise returns boolean false
	 */
	
	function get_user_db_id($fb_app_user_id){

		$users = $this->db->rawQuery('SELECT * from users WHERE fb_app_user_id = ?', Array ($fb_app_user_id));

		if(count($users) > 0){
			return $users[0]['id'];
		} else {
			return false;
		}
	}

	/**
	 * Add user to database
	 * @param  string  $fb_app_user_id   ID of user in the Facebook app
	 * @param  string  $name             Name of user from Facebook
	 * @param  string  $email            Email of user from Facebook
	 * @param  string  $picture_url      URL of user's picture from Facebook
	 * @return int|boolean               Row ID of user in database
	 */
	
	function add_user($fb_app_user_id, $name, $email, $picture_url){
		$data = Array (
				"fb_app_user_id" => $fb_app_user_id,
               "name" => $name,
               "email" => $email,
               "picture_url" => $picture_url,
               "created_at" => date("Y-m-d H:i:s"),
               "updated_at" => date("Y-m-d H:i:s")
		);
		$new_id = $this->db->insert ('users', $data);
		if($new_id){
			return $new_id;
		} else {
			return false;
		}
	}

	/**
	 * Get user data for profile page
	 * @param   int  $user_id  Row ID of user in the database
	 * @return  array|boolean  Array with user data, otherwise boolean false
	 */

	function get_user_data($user_id){
		$user = $this->db->rawQuery('SELECT * from users WHERE id = ?', Array ($user_id));
		if(count($user) > 0){
			return $user[0];
		} else {
			return false;
		}	
	}

}


MysqliDb.class.php for Login via Facebook

For my database interactions, I use a premade class called MysqliDb.class.php, written by Jeffery Way, Josh Campbell, and Alexander V. Butenko.

The following is a download link to MysqliDb.class.php from Dropbox.

  MysqliDb.class.php (unknown, 79 hits)

style.css CSS for Login via Facebook

Just simple styling for the display.

*{
	font-family: sans-serif;
}

.label{
	font-weight: bold;
}

#footer{
    margin-top:50px;
    padding-top:10px;
    border-top:1px solid #ccc;
}
#footer, #footer a{
    color: #999;
}

#messages .message{
    padding: 10px;
    border: 1px solid #E29C9C;
    margin: 10px 0;
    font-size: .8em;
}
#messages .error{
    border: 1px solid #E29C9C;
    background-color: #FFEBEB;	
}
#messages .success{
    border: 1px solid #9CE29C;
    background-color: #EBFFED;
}
loading.gif image for Login via Facebook

Right click on the following GIF image, then choose to "Save image as…"

Right click on this then choose to "Save image as..."

 

login.js JavaScript for Login via Facebook

First off, please remember to set your Facebook App ID as the value of the variable the_app_id at the beginning of login.js. The app won’t work without it.

This JavaScript is the core of our Facebook login system. The user needs to be logged in to Facebook and needs to authorize the app we are making to retrieve user data.

You will see here how we can call a function with a dynamic name. For example, you have two available functions: function A(){} and function B(){}. You can have a condition to determine which of the two functions the script should call, like, if(condition===true){ var func_name = "A"; } else { var func_name = "B"; } When it’s time to call the function, based on the condition check performed, you type this: window[func_name](). Whatever value was assigned to the variable “func_name” is the name of the function that will be run by JavaScript.

Try to analyze this login.js script, and you’ll realize that to decide whether we’ll call the function named init_fb_login or fb_get_user_data, we check if it’s the first time that the Login via Facebook button has been clicked.

Originally, my script always called the window.fbAsyncInit function that contains FB.init regardless of how many times the button’s been clicked. But that setup only let the Facebook login work on the first click.

So I revised my script so that if it’s the first click on the button, we’ll run init_fb_login() because that is where FB.init() is. And from the second click onward, we would always call fb_get_user_data().

Reminder: Set your Facebook App ID as the value of the variable the_app_id at the beginning of login.js. The app won’t work without it.

/**
 * Variable setup
 * Remember to set your Facebook App ID here
 */

var the_app_id = '<YOUR-FACEBOOK-APP-ID>';
var first_click = true;

/**
 * Fire when Login Via Facebook button is pressed
 */
 
function fb_login(){

  /**
   * Run function based on whether
   * it's the first time the button is clicked
   * Function name is dynamic
   */
    if(first_click===true){
        var func_name = 'init_fb_login';
    } else {
        var func_name = 'fb_get_user_data';
    }

    /**
     * Set first_click to false now,
     * since this function is fired on click
     */
    
    first_click = false;

    /** 
     * Show loading.gif
     */

    $('#loading_gif').css('visibility','visible');

    /**
     * Call function by dynamic name then CALLBACK
     */

    window[func_name](function(fb_login_data){
        /**
         * If no Facebook data fetched
         */
        if(fb_login_data === false){
            $('.message.auth-failed').show();
            $('#loading_gif').css('visibility','hidden');
        }

        ajax_fb_login(fb_login_data);
        
    });
}

function ajax_fb_login(fb_login_data){
    
    if(fb_login_data != false) {
         $.ajax({
            type    : 'POST',
            dataType: "json",
            url     : 'controllers.php?p=check_fb_data',
            data    : { 'fb_app_user_id': fb_login_data.id, 'name': fb_login_data.name, 'picture_url': fb_login_data.picture.data.url  },
            success : function(data){
                if(data.success == true){
                    var success_msg = $('.message.success').html();
                    success_msg = data.message + " " + success_msg;
                    $('.message.success').html(success_msg);
                    $('.message.success').show();
                     window.setTimeout(function(){
                        // SET SESSION FOR LOGIN!               
                        var redirect_url = "index.php";
                        
                        $(location).attr('href', redirect_url)
                    }, 2000);               
                } else {  
                    $('.message.auth-failed').show();
                }
                $('#loading_gif').css('visibility','hidden');

            }
        });       
    }    
}

/**
 * Call this function directly AFTER first click
 * On first click, we call a different function
 * which calls this too
 */

function fb_get_user_data(callback){
        FB.getLoginStatus(function(response) {
          /**
           * If already logged in to Facebook from the web browser
           */
          if (response.status === 'connected') {
                /**
                 * Fetch Facebook data
                 */
                 FB.api('/me?fields=id,name,email,picture', 'get', function(response) {
                    /**
                     * Pass response to callback function
                     */
                    callback(response);
                 });            
          }
          /**
           * If not yet logged in
           */
          else {
            /**
             * Ask user to login
             */
             FB.login(function(response) {
              /** 
               * If Facebook login was successful
               */ 
               if (response.authResponse) {
                /**
                 * Fetch Facebook data
                 */
                 FB.api('/me?fields=id,name,email,picture', 'get', function(response) {
                   callback(response);
                 });
               }
               /**
                * If Facebook login was not successful
                */
               else {
                  /**
                   * Pass boolean false to callback
                   */
                 callback(false);
               }
             });
          }
        });   
}

/**
 * Initiate Facebook
 * On first click of Login button
 */

function init_fb_login(callback){
    
    window.fbAsyncInit = function() {
        /**
         * Initiate FB object
         */
        FB.init({
            appId      : the_app_id,
            cookie     : true,  
            xfbml      : true,
            version    : 'v2.4',
            oauth      : true
        });
        /**
         * Get Facebook user data
         */
        
        fb_get_user_data(callback);

      };

    /*
     * Load the SDK asynchronously
     */ 
    
    (function(d, s, id){
        var js, fjs = d.getElementsByTagName(s)[0];
        if (d.getElementById(id)) {return;}
        js = d.createElement(s); js.id = id;
        js.src = "//connect.facebook.net/en_US/sdk.js";
        fjs.parentNode.insertBefore(js, fjs);
    }(document, 'script', 'facebook-jssdk'));

    
}

Download link to my codes for “Login via Facebook”

Feel free to download and use the codes I’m sharing:

  Login via Facebook - August 2015 Codes (unknown, 74 hits)

Troubleshooting

“App Not Setup: This app is still in development mode, and you don’t have access to it. Switch to a registered test user or ask an app admin for permissions.

Add email to make app live (login via facebook tutorial)

In the Facebook Developers site, go to your app then Settings -> Basic, then enter your email address on the field “Contact Email”. Before you make your Facebook app live, you are required to enter an email address.

Make Facebok app live (login via facebook tutorial)

Once you enter an email address in Settings -> Basic, you may now make your Facebook app live. To the right side of the message “Do you want to make this app and all its live features available to the general public?”, click the button that says “NO” to toggle it.

I can’t promise to be able to help with every issue you might encounter, but feel free to post questions in the comments section, and please try to help each other out. πŸ™‚

Related Posts:

Posts that may be related to "How to make a basic “Login via Facebook” with PHP & JavaScript":

Catzie

A Filipino programmer and baker. When I have time to spare, I blog, play video games, watch series (usually anime), cook dishes, draw, or spend a little time with pets. When I have the rare luxury of time, I get to travel and record song covers too! Running small-time online dessert shops Cookies PH and Catzie's Cakery.

One comment on “How to make a basic “Login via Facebook” with PHP & JavaScript

 

Leave a Reply

Your email address will not be published. Required fields are marked *