可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have the following code which redirects the user to log into facebook and tries to retrieve the session but the session is NULL:
<?php
session_start();
require 'vendor/autoload.php';
use Facebook\FacebookSession;
use Facebook\FacebookRedirectLoginHelper;
FacebookSession::setDefaultApplication('Foo', 'Bar');
$helper = new FacebookRedirectLoginHelper('Baz');
$loginUrl = $helper->getLoginUrl();
echo '<a href="' . $loginUrl . '">Log In</a>';
$session = $helper->getSessionFromRedirect();
// This displays [NULL] always
echo '[' . gettype($session) . ']';
?>
I don't understand why the $session is always NULL. Please help.
回答1:
It happens because of the getLoginUrl() function,
because when we mentioned same page as FB redirect page, it call getLoginUrl()
function again and again.. which change $this->state
variable value
and then isValidRedirect()
and getSessionFromRedirect()
always return null
Here is solution to use same page as FB redirection page:
Don't call getLoginUrl()
when facebook redirect you to same page, just add the proper session check to check valid facebook session (Please refer following code example)
session_start();
require("facebook/autoload.php");
use Facebook\FacebookSession;
use Facebook\FacebookRedirectLoginHelper;
use Facebook\GraphUser;
use Facebook\FacebookRequestException;
FacebookSession::setDefaultApplication('appid84', '0secret0a626c6');
$helper = new FacebookRedirectLoginHelper('http://tmd.local/fblogin.php');
try {
$session = $helper->getSessionFromRedirect();
// var_dump($session);
} catch(FacebookRequestException $ex) {
} catch(\Exception $ex) {
}
if ($session) {
var_dump($session);
}
else
{
$loginUrl = $helper->getLoginUrl();
header("location:".$loginUrl);
exit;
}
回答2:
You should be calling getSessionFromRedirect only on the page Facebook redirects the user to after login. Then store that session somewhere, like $_SESSION, and re-use it elsewhere.
The issue is, when you generate the login url again, it changes the 'state' variable used to protect against CSRF.
回答3:
Ok, so the goal was to get a FacebookSession
. There needs to be 2 pages: 1 for displaying the Log In link and the other to accept the instance of FacebookSession
. In page1.php put:
<?php
session_start();
require 'vendor/autoload.php';
use Facebook\FacebookSession;
use Facebook\FacebookRedirectLoginHelper;
FacebookSession::setDefaultApplication('foo', 'bar');
$helper = new FacebookRedirectLoginHelper('page2.php');
$loginUrl = $helper->getLoginUrl();
echo '<a href="' . $loginUrl . '">Log In</a>';
?>
In page2.php put:
<?php
session_start();
require 'vendor/autoload.php';
use Facebook\FacebookSession;
use Facebook\FacebookRedirectLoginHelper;
FacebookSession::setDefaultApplication('foo', 'bar');
$helper = new FacebookRedirectLoginHelper('page2.php');
// Now you have the session
$session = $helper->getSessionFromRedirect();
?>
Thanks Fosco for your help.
回答4:
You can do the session loading, login redirect and API call all from the single page if required. This tutorial shows you how it can be done.
回答5:
I had the same problem doing all of the above, and I fixed it by
Changing the App Setting. Facebook Developers -> My App -> Settings -> Advanced -> Valid OAuth redirect URIs -> Add '/' at the end of the directory. If it's a file, then end the path at the directory that the file is in.
回答6:
Look at those two docs, those will help you resolving :)
https://developers.facebook.com/docs/php/gettingstarted
https://developers.facebook.com/docs/php/howto/profilewithgraphapi
回答7:
There is a bug in the FacebookRedirectLoginHelper.php line 214!
change the $_GET['state'] with $_SESSION['state'] from this way:
/**
* Check if a redirect has a valid state.
*
* @return bool
*/
protected function isValidRedirect()
{
$savedState = $this->loadState();
if (!$this->getCode() || !isset($_GET['state'])) {
return false;
}
$givenState = $_GET['state'];
$savedLen = mb_strlen($savedState);
$givenLen = mb_strlen($givenState);
if ($savedLen !== $givenLen) {
return false;
}
$result = 0;
for ($i = 0; $i < $savedLen; $i++) {
$result |= ord($savedState[$i]) ^ ord($givenState[$i]);
}
return $result === 0;
}
to this:
/**
* Check if a redirect has a valid state.
*
* @return bool
*/
protected function isValidRedirect()
{
$savedState = $this->loadState();
if (!$this->getCode() || !isset($_SESSION['state'])) {
return false;
}
$givenState = $_SESSION['state'];
$savedLen = mb_strlen($savedState);
$givenLen = mb_strlen($givenState);
if ($savedLen !== $givenLen) {
return false;
}
$result = 0;
for ($i = 0; $i < $savedLen; $i++) {
$result |= ord($savedState[$i]) ^ ord($givenState[$i]);
}
return $result === 0;
}
回答8:
What made the real difference to me was the redirect Url address i was using.
Hours and hours because of a slash.
Explaining with examples:
(Wrong)
$helper = new FacebookRedirectLoginHelper('http://www.example.com');
(Right)
$helper = new FacebookRedirectLoginHelper('http://www.example.com/');
I've read a ton of tutorials and answers on Stackoverflow and this final slash was the real answer. I hope it helps someone