Facebook JS SDK and PHP SDK Access Token Conflict [closed]
I have scoured StackOverflow and even submitted a bug to facebook with no help. I have spent a solid 40+ hours nailing this down. I belive it to be a conflict between the FB.INIT and the PHP access token, when a server has heavy .htaccess Mod Rewrites to alter the url to a valid query string. I have written it up as a bug but Facebook believes it's a user issue. I have even used the code in their answer and it is still bugged.
Here is the original problem. On my test sites I can get the PHP SDK with the JS SDK to work just fine. Both allow logins and work in harmony communicating with each other. No problems when surfing pages or performing all the functions I'm about to update a client with.
Now I'm trying to install the new OAuth updated into my clients site with heavy .htaccess mod Rewrites. Where my test site had no Mod ReWrites.
At first you could log in with PHP just fine. But once you went to another page within the site you lost your Access token with the popular error: An active access token must be used to query information about the current user.
This was fixed by checking to see if the PHP api failed and then using a file_get_contents command taken from Facebook's own authorization page (against: https://graph.facebook.com/oauth/access_token?) and resetting the access token. This worked. But this then caused the FB.init to fail with the response error: An active access token must be used to query information about the current user. Callbacked by FB.api('/me')
So to get around this I had to pass PHP's access token into a SESSION and place it in my api calls. Like so, FB.api('/me/?access_token='). This worked. So now my site works with Facebook through dominate PHP with JS being a secondary.
CURRENT ISSUE: If a user comes to the site and is not logged into the standard PHP Facebook function and uses a function that uses FB JS SD; The site prompts a JS Login with appropriate permissions for that site function. The user accepts and Logs-In. Everything is fine from a JS stand-point. The console.log dumps tell me this from page to page.
PROBLEM: The PHP will not acknowledge the Access_token from the cookie set by JS SDK, nor will it receive a cookie from file_get_contents (kicks back a failed HTTP Request 400). So wile the user is logged in through the JS, the PHP will not accept their login and still show the PHP getLoginUrl function.
When a var_dump is performed on the PHP facebook object we see all fields contain data; code, state, access_token, algorithm and more. But when a $facebook->api('/me') on every page (which was successful above) is performed we receive the error: An active access token must be used to query information about the current user.
My Conclusion: There is a mismatch Code generation based off the perceived URL of JS and the actual url of PHP. Where it's easier to force JS to a PHP access token the same can't be done for PHP to be dominated by JS.
Here's the PHP code on every page.
$app_id = 'APP_ID';
$app_secret = 'APP_SEC';
$my_url = 'http://'.$_SERVER['HTTP_HOST'];
$facebook = new Facebook(array(
'appId' => $app_id,
'secret' => $app_secret,
));
$_SESSION[fbappID] = $facebook->getAppId();
$_SESSION[fbaccTok] = $facebook->getAccessToken();
$sigReq = $facebook->getSignedRequest();
$code = $sigReq[code];
$userID = $facebook->getUser();
if($userID)
{
try {
$user_profile = $facebook->api('/me');
} catch (FacebookApiException $e) {
error_log($e);
$token_url = "https://graph.facebook.com/oauth/access_token?"
. "client_id=" . $app_id . "&redirect_uri=" . urlencode($my_url)
. "&client_secret=" . $app_secret . "&code=" . $code;
$response = file_get_contents($token_url);
$params = null;
parse_str($response, $params);
if($params[access_token]!="")
{
$facebook->setAccessToken($params[access_token]);
$_SESSION[fbaccTok] = $facebook->getAccessToken();
}
try{
$user_profile = $facebook->api('/me');
}catch(FacebookApiException $e) {
error_log($e);
$userID = null;
}
}
}
if($userID)
{
$user_profile = $facebook->api('/me');
$logout = $facebook->getLogoutUrl();
}
else
{
$login = "<a href='".$facebook->getLoginUrl()."'>Log In with Facebook</a>";
}
The Javascript used:
<script>
FB.init({
appId : '$_SESSION[fbappID]',
status : true,
cookie : true,
xfbml : true,
oauth : true
});
FB.api('me/permissions/?access_token=<?php print $_SESSION[fbaccTok]?
>',function(response){c开发者_运维问答onsole.log(response)});
</script>
ANSWER:
Here is the answer: To allow Javascript to be the main point of entry. You can't have both. You must choose one, PHP or javascript and make them the dominate to force the other's Access Token. Here is the Javascript:
window.fbAsyncInit = function() {
FB.init({
appId : '12345',
channelURL : '/channel.php',
status : true,
cookie : true, // enable cookies to allow the server to access the session
xfbml : true, // parse XFBML
oauth : true //enables OAuth 2.0
});
FB.getLoginStatus(function(response){
if(response.authResponse){
FB.accessToken = ;
createCookie('fbToken',response.authResponse.accessToken,.1);
createCookie('fbID',response.authResponse.userID,.1);
}
});
FB.Event.subscribe('auth.login', function(response) {
createCookie('fbToken',response.authResponse.accessToken,.1);
createCookie('fbID',response.authResponse.userID,.1);
createCookie('fbLogin',1,30);
window.location.reload();
});
FB.Event.subscribe('auth.logout', function() {
eraseCookie('fbLogin');
eraseCookie('fbToken');
eraseCookie('evFB.uid');
});
}
createCookie and eraseCookie are cookie functions which can be found through the net. This is the rough code not the refined. Basically I create my own Cookies to pass information. Since FB JS SDK refreshes pages on login and logout, I can delete and create cookies or modify them before PHP takes over on a page refresh.
Now here's the PHP that is forced the JS cookie access token.
require_once("/facebook.php");
$facebook = new Facebook(array(
'appId' => $app_id,
'secret' => $app_secret,
));
$my_url = $facebook->returnGetUrl();
$_SESSION[fbaccTok] = (isset($_COOKIE[fbToken]))?$_COOKIE[fbToken]:$facebook->getAccessToken();
$sigReq = $facebook->getSignedRequest();
$code = ($_REQUEST[code]=='')?$sigReq[code]:$_REQUEST[code];
$GLOBALS[fbUser]= $facebook->getUser();
if(isset($_COOKIE[fbLogin]))
{
if($_COOKIE[fbLogin]==1)
{
$GLOBALS[fbUser] = $facebook->getUser();
//print $GLOBALS[fbUser];
}
else
{
$GLOBALS[fbUser] = null;
}
}
else
{
$GLOBALS[fbUser] = null;
}
if($GLOBALS[fbUser] && $_COOKIE[fbToken])
{
$GLOBALS[fbArray] = array(
'access_token' => $_COOKIE[fbToken]
);
try {
$GLOBALS[fbUserProfile] = $facebook->api('/me','GET',$GLOBALS[fbArray]);
//print_r($GLOBALS[fbUserProfile]);
} catch (FacebookApiException $e) {
error_log($e);
}
}
Hope this helps.
if it works without the mod rewrites but not with the mod rewrites, then that is the issue,
what you could do is create another facebook test application and host in on a separate server without mod rewrites, then gradually add in the mod rewrites 1 at a time until the problem happens, to see which one is causing it.
精彩评论