Check if Facebook user is logged in to app with PHP SDK - php

I have an app using the Facebook Login API. I take the details of the user and store it in my own database and create my own user id for the user (I also store the facebook id).
Next time the user visits my site, I want to automatically set the session, without having them reconnecting again. So I want to get the Facebook ID of the user (If he is already authenticated) and then check in my database if that ID exists, if so then I set the session.
This is described in the Javascript SDK, however the problem with the Javascript SDK is that the user will not be logged in when visiting the first page, only after a page refresh (Since the Javascript is run after the PHP is executed, so the session is not set when the page loads).
So I want to do this server side, using the PHP SDK.
I tried the following code:
public function isUserLoggedIn(){
$facebook = new Facebook();
$user = $facebook->facebook->getUser();
if($user){
//Use API call for /me which require authentication
try{
$me = $facebook->facebook->api('/me');
//If id_facebook exist, then set logged in session to user id
if($me){
$stmt = $GLOBALS['link']->prepare('SELECT * FROM users WHERE id_facebook=:id_facebook');
$stmt->execute(array('id_facebook' => $me['id']));
if($row = $stmt->fetch()){
$_SESSION['uid'] = $row['id'];
}
}
} catch (FacebookApiException $e) {
$user = null;
//User is not logged in
}
}
}
This code only passes when the Javascript SDK has already authenticated the user and he is logged in. It does not work as intended.
So:
How do I use the PHP SDK to check if the user is authenticated with my App?
I could just set a $_COOKIE myself, is that the way to do it? I suppose that there is an "official" way using the SDK/API, since there is with the Javascript SDK.

I feel I'm a bit late, but here's my two cents:
I log into SO using facebook. Sometimes, in fact, after a day or so passed, i land on this site and after a second or two a little popup tells me that I've been logged in and to refresh the page. It's not really an issue, I just reload the page and I'm happy. That's what you're referring to.
But remember, should you only check the session to retrieve user's ID and facebook data, could lead to problems when the users logged out from facebook (or from your app): your session is not up-to-date with facebook.
That's why using Javascript SDK to login should be better.
I've done a lot of tests and trials today, to understand how the whole thing works (mainly because I encountered a lot of wrong or not complete information given by many "tutorials" out there). The version that did work is the one absolutely copy/pasted from Facebook guide to PHP SDK. Supposing there's an already configured Javascript SDK, I opened my index.php page and started with SDK inclusion:
//autoload is needed to include all sdk classes (not needed using Composer)
require_once ('./inc-fb-sdk/autoload.php');
Then, I had to explicitly tell the SDK to load some of the included classes; this is needed to make use of those classes:
use Facebook\FacebookJavaScriptLoginHelper;
use Facebook\FacebookRedirectLoginHelper;
use Facebook\FacebookRequest;
use Facebook\FacebookResponse;
use Facebook\FacebookSDKException;
use Facebook\FacebookSession;
use Facebook\FacebookRequestException;
use Facebook\GraphObject;
use Facebook\GraphUser;
And, of course, we initialize PHP SDK creating the object (use your AppID and AppSecret in the following line):
FacebookSession::setDefaultApplication('App_id', 'App_secret');
Finally, this is the code from the Guide, with some added comments and echoes, to show if user is logged in or not:
//create object that is used to check login
$helper = new FacebookRedirectLoginHelper();
try {
$session = $helper->getSessionFromRedirect();
} catch(FacebookRequestException $ex) {
// When Facebook returns an error
} catch(\Exception $ex) {
// When validation fails or other local issues
}
//show if the user is logged in or not
if ($session) {
// Logged in
echo ('User is logged in');
} else {
echo ('User is not logged in');
}
Since you're already using the Login API, you only have to test loggin in/out from facebook and then refresh the page, to see the various situations that could happen.
And this should answer the two questions at the end of your post.
Hope this helps.
Note from #parse
You need to pass redirectUrl when you try to call FacebookRedirectLoginHelper(redirectUrl), otherwise you will get 'Missing argument' warning followed by this notice 'Undefined variable: redirectUrl in FacebookRedirectLoginHelper.php on line 77'

Related

Get user ID using Facebook PHP SDK 4

Following this discussion i can't figure it out how to getUserId from session or how to create session from a signed request in new SDK 4 for PHP? I'm trying to migrate my apps from old SDK to new one and my code doesn't work well.
I'm trying to get the user ID on page tab where i'm an admin. I've tried to getSession from FacebookPageTabHelper with no luck.
My php code:
session_start();
require_once '../api/facebook/autoload.php';
use Facebook\FacebookSession;
use Facebook\FacebookPageTabHelper;
FacebookSession::setDefaultApplication(APP_ID, APP_SECRET);
$pageHelper = new FacebookPageTabHelper();
$page = $pageHelper->getPageId();
$admin = $pageHelper->isAdmin();
$fan = $pageHelper->isLiked();
$appdata = $pageHelper->getSignedRequest()->payload['app_data'];
$session = $pageHelper->getSession();
$user = $session->getUserId(); // always empty
Facebook API doesn't provide you with this information anymore (if you use the user access token). You should get the ID of the user by looking at his posts or his comments, and even by this way you need to guess that he is a public user otherwise it will not work.
If you can login with the app token it should work but it's not easy to get confirmation for your application by Facebook.

Facebook php api giving access to users with invalid tokens

I am using the facebook php api to control the access to some parts of my webapp. Basically I am just checking if the user is logged into facebook and the user authorize the app (basic permission) every time the page is load and then printing things according to the state.
Something like, if($check_user_lo_npe) { echo 'Welcome!'; }, simple as that. Well, everything is working fine, until I realize that if the user deletes the app from their users settings in facebook, which means the token gets invalidated, I am still getting a true response from the function check_user_lo_npe even if I know the token is invalid because as I said, the user deleted the app. This is how I am checking the permissions:
function check_user_lo_npe() {
global $facebook;
global $data;
$fb_user_id = $facebook->getUser();
if ($fb_user_id) {
try {
if(!isset($_SESSION['fb_user_profile'])) {
$_SESSION['fb_user_profile'] = $facebook->api('/me');
$temparray = $facebook->api('/me/friends');
$_SESSION['fb_user_friends'] = count($temparray[data]);
}
$data->reg_user($_SESSION['fb_user_profile'],$_SESSION['fb_user_friends']);
return array(true,'');
} catch (FacebookApiException $e) {
$fb_user_id = NULL;
return array(false,$e->getMessage());
}
} else {
return array(false,'');
}
}
I need to realize when the user deletes the app so I can send them to the login screen again, the function is supposed to detect when there is an exception, but somehow I am not getting any... why?
Those $_SESSION variables are set by your app, not by the Facebook SDK right?
Without attempting to access the Facebook session you can't be sure if that session is still active/
If you need to check on each page whether there's still an active Facebook session or not, look at FB.GetLoginStatus() in the Javascript SDK, or make an API call to (for example) /me/permissions to check your access token is still valid
That said, it may be as easy to just have an exception handler which detects when an attempt to access Facebook's API fails, and have it send the user through the authentication flow at that point.
Your if ($fb_user_id) line is probably evaluating to false, which causes you to return array(false,''); in your else statement, never triggering an exception.
If you did get past the ID check, it looks like you are putting data into $_SESSION before they delete the app, and then not re-checking it. Once you have it in the $_SESSION, if you don't go back to Facebook to verify, there is no reason an exception would be thrown.

Facebook connect is very slow, can I use AJAX?

I'm implementing the facebook php sdk and using it for user login/connect.
Everything works as expected, however, at the top of each page, I need to call
$facebook->api('/me') to determine if the user is logged in or not..
This call is very slow, sometimes, taking up to 2 seconds to return.
So, any interaction by the user, always has a 1-2 sec delay before any page loads..
I suspect, it's because, the $facebook->api('/me') call is using httpS ..
Any suggestions....
$facebook = new Facebook(array( 'appId' => 'xxxxxxxxxxxxxxx', 'secret' => 'xxxxxxxxxxxxxxxxx',));
$user = $facebook->getUser();
if ($user)
{
try { $user_profile = $facebook->api('/me','GET'); }
catch (FacebookApiException $e) { error_log($e); $user = null; }
}
$login_parms = array('scope' => 'user_birthday', 'redirect_uri' => 'http://xxx.com/login');
$login_link = $facebook->getLoginUrl($login_parms);
if($user)
{
/* logged in */
}
else
{
/* not */
}
You really shouldn't perform the Facebook API request on each page load. Only do it once when the user logs in. Then you can store the "logged in" flag in the session (or a signed cookie).
If you need to store e.g. some of the user's facebook profile information, also put it in the session or your database.
Add some spinning wheel where login form is, then call ajax on document ready to your php script, script returns false or loged in user data (or more data if you need - redirect url) and then depending on result show form to login or display currently loged in user.
What i mean Javascript will handle all logic depending on what is returned from server, redirects, change UI etc.
Another way is to cache (session with expiration) first call to facebook if user is loged in remember it. And check if that Session variable is present and not yet expired. Only call again when doing some sensitive tasks or get expired.
If you do not need to get "fresh" values from $facebook->api("/me").
Then I would suggest you cache the response, if you use any PHP-framework (eg. Zend, Yii, Codeigniter) this should be really straight forward.
If you're not using a PHP-framework i suggest you still look into the excellent ZF documentation for their cache solution.
Zend Framework - Cache
If you, however, need fresh values each load you can make a simple page that only returns the $facebook->api("/me") part and returns it as bare HTML. Then simply keep a or similar that recieves the response when it's finished.
An easy solution would be using jQuery and just write:
$("#div-id").load("/page-that-returns-facebook-api-me-result");

facebook connect api static url

Is there a way to use the facebook connect api in a static way?
When we use the facebook php sdk the link or button to login to facebook is something like https://www.facebook.com/dialog/oauth..................
what I want is to eliminate the include of the php sdk on every page, because it will cause some extra processing and server load in peak times.
I want to make a session check to know if the user is logged in, by checking for exemple if his facebook user id and name are stored in the session, then if not, display a static login button. then after login with facebook he gets to facebook-login.php which will include the facebook php sdk and process his data and store them in the session, so that he remains logged without including the php sdk in each page.
the url structure that I get with $facebook->getLoginUrl() is:
https://www.facebook.com/dialog/oauth?client_id={MY_APP_KEY}&scope={PERMISSIONS}&redirect_uri={MY_SITE/facebook-login.php}&state={A_32_CHAR_CODE_LIKE_MD5_MAYBE}
The final question is: WHAT WOULD BE THE URL IN THE LOGIN BUTTON?
just load the sdk and do something like:
echo 'Connect to Facebook';
that url will always be valid for a logged out user
This is a good question. First, a user is logged into you app means that you have a valid access token for the user.
And there is no way to be sure that an access token is valid before making an API call with this access token. So if you want to make sure the user is still logged in on each page, you have to make an API call to Facebook on each of them. Kind of heavy, but there is no other solution.
What you can do is assume that the access token you have is valid and check only once a while (when you really need to be sure the user is logged in).
You can have different scenario :
you have no Facebook data about the user : the user is not logged in your app for sure.
you can read the user ID, but you may not have an access token for this user : the user may not be logged in.
you can read an access token, but it may not be valid (has expires or revoked by the user) : the user may not be logged in.
you have a valid access token : the user is logged in for sure.
You can read the user ID and the access token in the session. The session array looks like that :
[fb_148195765253871_access_token] => 14819576525...
[fb_148195765253871_user_id] => 1536397056
The number in the keys of the array (here 148195765253871) is your app ID.
So what you can do on each page is to check if those keys are set and if they are not, load the SDK and double-check (because the access can be store in some other places that the SDK is reading) :
if (isset($_SESSION['fb' . YOUR_APP_ID . 'access_token'])) {
// assume to user is logged in
// and keep going
} else {
require "facebook.php";
$facebook = new Facebook(array(
'appId' => YOUR_APP_ID,
'secret' => YOUR_APP_SECRET,
));
// Make an API call to be sure the user is logged in
// ie : that you have a valid access token
$user = $facebook->getUser(); // User ID
if ($user) {
try {
$user_profile = $facebook->api('/me');
} catch (FacebookApiException $e) {
$user = null;
}
}
if ($user) {
// The user is logged in for sure
} else {
// The user is not logged in for sure
// Make him log in
echo 'Login with Facebook';
}
}
Hope that helps !
The selected answer does not really answer the question.
If you would like to isolate all the Facebook code necessary for generating the getLoginUrl function call into a separate file you can do this easily by using meta refresh.
So in your header point the link "Login With Facebook" to "facebook_login.php". On this page include the necessary calls from the SDK for getLoginUrl and than add the following line of HTML.
<meta http-equiv="refresh" content="0;URL=<?=$helper->getLoginUrl(array('email', 'user_friends'));?>">
I tested this out multiple times and it works.
FYI using Facebook SDK 4.0.

Testing whether a Facebook session is valid?

I'm not sure if the php server side Facebook library validates sessions on load. So then I want to know if there is a best practice for insuring that I really do have a valid FB session and not some crackers altered $_COOKIE data.
$fb = new Facebook();
if( $fb->session_expires !== 0 && $fb->session_expires < time() ) {
die('bad and/or old session');
}
or is it better to test the users FB id?
$fb = new Facebook();
if( $fb->user ) {
die('no Facebook User Id given');
}
EDIT:
Ok, according to facebook "Your client library should perform all the necessary validation for you" by using the application secret to md5 all the params and validate the hash. So if you have a session - it is a valid FB generated one (although it can still be expired).
Suppose that you login to a connect app. Then you logout of FB. If you load another page on that connect app then there has not been any chance for the FB JS to change the cookies to state that you are actually logged out. And since the PHP library doesn't actually call FB to validate your session it also can't know to remove the bad values.
The result is that you have a valid set of cookies sent from FB that are no longer any good. So should you try to call an API method that requires a session then your app will throw a fatal error.
Call an API method $facebook->getUser() and that should check whether the user is valid.
https://github.com/facebook/facebook-php-sdk/blob/master/src/base_facebook.php#L508
As in the example provided in the SDK
// Get User ID
$user = $facebook->getUser();
// We may or may not have this data based on whether the user is logged in.
//
// If we have a $user id here, it means we know the user is logged into
// Facebook, but we don't know if the access token is valid. An access
// token is invalid if the user logged out of Facebook.
if ($user) {
try {
// Proceed knowing you have a logged in user who's authenticated.
$user_profile = $facebook->api('/me');
} catch (FacebookApiException $e) {
error_log($e);
$user = null;
}
}
A late answer but, currently Facebook PHP class have a getSession() method:
if ($facebook->getSession()) {
// Do stuff
}

Categories