Gco*_*oop 7 php facebook facebook-graph-api
我正在尝试使用存储的长期访问令牌,但在2小时后,我从图API中得到以下错误.我已经写了一些代码,将用户发送至Facebook获取可用于访问令牌,这工作得很好,除了这发生在每个后续页面请求予以更换新代码,Facebook的继续我的访问令牌与下面的错误无效,尽管他们的服务器返回了访问令牌.
Error validating access token: Session has expired at unix time 1338300000. The current unix time is 1338369365.
Run Code Online (Sandbox Code Playgroud)
完整的测试页面示例如下.由于显而易见的原因省略了我的钥匙.击中页面,登录,然后将其搁置了几个小时,再次命中页面(你会得到重定向到Facebook和回用在URL中的代码),重新加载页面,它会不断地重定向到Facebook和回虽然我告诉它使用它刚刚为所述代码返回的访问令牌.
<?php
require 'facebook.php';
$app_id = APP_ID;
$app_secret = APP_SERCRET;
$my_url = URL;
$facebook = new Facebook(array(
'appId' => $app_id,
'secret' => $app_secret
));
// known valid access token stored in a database
$access_token = isset($_COOKIE["FB_LONG_AC_TOKEN"]) ? $_COOKIE["FB_LONG_AC_TOKEN"] : false;
$code = $_REQUEST["code"];
// If we get a code, it means that we have re-authed the user
//and can get a valid access_token.
if (isset($code)) {
$token_url="https://graph.facebook.com/oauth/access_token?client_id="
. $app_id . "&redirect_uri=" . urlencode($my_url)
. "&client_secret=" . $app_secret
. "&code=" . $code . "&display=popup";
$response = file_get_contents($token_url);
$params = null;
parse_str($response, $params);
$access_token = $params['access_token'];
}
// Attempt to query the graph:
$graph_url = "https://graph.facebook.com/me?"
. "access_token=" . $access_token;
$response = curl_get_file_contents($graph_url);
$decoded_response = json_decode($response);
//Check for errors
if ($decoded_response->error) {
// check to see if this is an oAuth error:
if ($decoded_response->error->type== "OAuthException") {
// Retrieving a valid access token.
$dialog_url= "https://www.facebook.com/dialog/oauth?"
. "client_id=" . $app_id
. "&redirect_uri=" . urlencode($my_url);
echo("<script> top.location.href='" . $dialog_url
. "'</script>");
}
else {
echo "other error has happened";
}
}
else {
// success
echo("Success: ".$decoded_response->name."<br />");
echo($access_token."<br />");
// Attempt to convert access token to longlife token if we don't have one stored.
if (!isset($_COOKIE["FB_LONG_AC_TOKEN"]))
{ // don't have long life token, so let's get one.
$ch = curl_init("https://graph.facebook.com/oauth/access_token?client_id=".$app_id."&client_secret=".$app_secret."&grant_type=fb_exchange_token&fb_exchange_token=".$access_token);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
$data = curl_exec($ch);
curl_close($ch);
$params = null;
parse_str($data, $params);
if (isset($params["access_token"]))
{
$access_token = $params["access_token"];
echo("Got long life token.<br />");
setcookie("FB_LONG_AC_TOKEN", $access_token, time() + (3600 * 24 * 60), "/");
}
}
else {
echo("Have long life token already.<br />");
}
}
if ($access_token) {
$facebook->setAccessToken($access_token);
// See if there is a user from a cookie
$user = $facebook->getUser();
if ($user) {
try {
// Proceed knowing you have a logged in user who's authenticated.
$user_profile = $facebook->api('/me');
} catch (FacebookApiException $e) {
echo '<pre>'.htmlspecialchars(print_r($e, true)).'</pre>';
$user = null;
}
}
}
// note this wrapper function exists in order to circumvent PHP’s
//strict obeying of HTTP error codes. In this case, Facebook
//returns error code 400 which PHP obeys and wipes out
//the response.
function curl_get_file_contents($URL) {
$c = curl_init();
curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($c, CURLOPT_URL, $URL);
$contents = curl_exec($c);
$err = curl_getinfo($c,CURLINFO_HTTP_CODE);
curl_close($c);
if ($contents) return $contents;
else return FALSE;
}
?>
<!doctype html>
<html xmlns:fb="http://www.facebook.com/2008/fbml">
<head>
<title>Facebook Auth</title>
</head>
<body>
<?php if ($user) { ?>
Your user profile is
<pre>
<?php print htmlspecialchars(print_r($user_profile, true)) ?>
</pre>
<?php } else { ?>
<fb:login-button></fb:login-button>
<?php } ?>
<div id="fb-root"></div>
<script>
window.fbAsyncInit = function () {
FB.init({
appId: <?php echo($app_id); ?>,
cookie: true, // enable cookies to allow the server to access the session
oauth: true, // enable OAuth 2.0
xfbml: true // parse XFBML
});
FB.getLoginStatus(function (res) {
console.log(res.status);
});
};
(function(d){
var js, id = 'facebook-jssdk'; if (d.getElementById(id)) {return;}
js = d.createElement('script'); js.id = id; js.async = true;
js.src = "//connect.facebook.net/en_US/all.js";
d.getElementsByTagName('head')[0].appendChild(js);
}(document));
</script>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
我究竟做错了什么?或者这是Facebook的问题?
更新:
我更新了我的代码以遵循@cpilko发布的流程但是我仍然遇到同样的问题.我可以登录和退出就好了.但是,如果我在几个小时后访问测试页面,请说第二天我使用提供的长寿命访问令牌获取Session过期异常(FB JS SDK认为我已连接,但服务器没有),我刷新页面我被显示为由服务器和FB JS SDK登录,我从facebook获得的长寿命令牌与我原来尝试过的(存储在我的cookie中)相同.我不明白的是为什么我第一次无法使用长寿命令牌.更新了以下代码.
<?php
require 'facebook.php';
$app_id = "XXXXXXXXXXXXX";
$app_secret = "XXXXXXXXXXXXXXXXXXXX";
$my_url = "http://swan.magicseaweed.local/facebook/";
$facebook = new Facebook(array(
'appId' => $app_id,
'secret' => $app_secret
));
$valid_user = false;
var_dump($_COOKIE);
echo("<br />");
if (isset($_COOKIE["FB_LONG_AC_TOKEN"]))
{ // Have long term token, attempt to validate.
// Attempt to query the graph:
$graph_url = "https://graph.facebook.com/me?"
. "access_token=" . $_COOKIE["FB_LONG_AC_TOKEN"];
$response = curl_get_file_contents($graph_url);
$decoded_response = json_decode($response);
// If we don't have an error then it's valid.
if (!$decoded_response->error) {
$valid_user = true;
$access_token = $_COOKIE["FB_LONG_AC_TOKEN"];
echo("Have long life token.<br />");
}
else {
// Stored token is invalid.
// Attempt to renew token.
// Exchange short term token for long term.
$ch = curl_init("https://graph.facebook.com/oauth/access_token?client_id=".$app_id."&client_secret=".$app_secret."&grant_type=fb_exchange_token&fb_exchange_token=".$facebook->getAccessToken());
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
$data = curl_exec($ch);
curl_close($ch);
$params = null;
parse_str($data, $params);
if (isset($params["access_token"]))
{
$access_token = $params["access_token"];
echo("Got long life token.<br />");
setcookie("FB_LONG_AC_TOKEN", $access_token, time() + (3600 * 24 * 60), "/");
}
else
{ // Clear invalid token.
setcookie("FB_LONG_AC_TOKEN", "false", time() - 3600, "/");
echo("Long life token invalid.<br />");
}
}
}
else if ($facebook->getUser())
{ // Have short term access token.
// Verify short term token is valid still.
try {
// Proceed knowing you have a logged in user who's authenticated.
$user_profile = $facebook->api('/me');
}
catch (FacebookApiException $e) { }
if (is_array($user_profile)) { // Have user.
$valid_user = true;
// Exchange short term token for long term.
$ch = curl_init("https://graph.facebook.com/oauth/access_token?client_id=".$app_id."&client_secret=".$app_secret."&grant_type=fb_exchange_token&fb_exchange_token=".$facebook->getAccessToken());
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
$data = curl_exec($ch);
curl_close($ch);
$params = null;
parse_str($data, $params);
if (isset($params["access_token"]))
{
$access_token = $params["access_token"];
echo("Got long life token.<br />");
setcookie("FB_LONG_AC_TOKEN", $access_token, time() + (3600 * 24 * 60), "/");
}
}
}
if ($access_token) {
$facebook->setAccessToken($access_token);
// See if there is a user from a cookie
$user = $facebook->getUser();
if ($user) {
try {
// Proceed knowing you have a logged in user who's authenticated.
$user_profile = $facebook->api('/me');
} catch (FacebookApiException $e) {
echo '<pre>'.htmlspecialchars(print_r($e, true)).'</pre>';
$user = null;
}
}
}
// note this wrapper function exists in order to circumvent PHP’s
//strict obeying of HTTP error codes. In this case, Facebook
//returns error code 400 which PHP obeys and wipes out
//the response.
function curl_get_file_contents($URL) {
$c = curl_init();
curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($c, CURLOPT_URL, $URL);
$contents = curl_exec($c);
$err = curl_getinfo($c,CURLINFO_HTTP_CODE);
curl_close($c);
if ($contents) return $contents;
else return FALSE;
}
?>
<!doctype html>
<html xmlns:fb="http://www.facebook.com/2008/fbml">
<head>
<title>Facebook Auth</title>
</head>
<body>
<?php if ($user) { ?>
Your user profile is
<pre>
<?php print htmlspecialchars(print_r($user_profile, true)) ?>
</pre>
<?php } else { ?>
<fb:login-button></fb:login-button>
<?php } ?>
<div id="fb-root"></div>
<script>
window.fbAsyncInit = function () {
FB.init({
appId: <?php echo($app_id); ?>,
cookie: true, // enable cookies to allow the server to access the session
oauth: true, // enable OAuth 2.0
xfbml: true // parse XFBML
});
FB.getLoginStatus(function (res) {
console.log(res.status);
});
};
(function(d){
var js, id = 'facebook-jssdk'; if (d.getElementById(id)) {return;}
js = d.createElement('script'); js.id = id; js.async = true;
js.src = "//connect.facebook.net/en_US/all.js";
d.getElementsByTagName('head')[0].appendChild(js);
}(document));
</script>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
当您的原始令牌过期时,您陷入循环的原因是您的代码不允许 Facebook 为您提供新令牌。当您收到 OAuth 错误时,您将调用 OAuth 对话框,该对话框不会使用新令牌重新填充您的 cookie。
您遇到的另一个问题是,在进行 api 调用之前,您要使用短期访问令牌覆盖长期访问令牌:
// known valid access token stored in a database
$access_token = isset($_COOKIE["FB_LONG_AC_TOKEN"]) ? $_COOKIE["FB_LONG_AC_TOKEN"] : false;
...
if ($access_token) {
$facebook->setAccessToken($access_token); //Loads the short-term token from a cookie!
Run Code Online (Sandbox Code Playgroud)
如果这是我的代码,我会使用两个变量:$access_token_temp这样$access_token_long我就可以把事情搞清楚。
编辑
您的页面加载工作流程需要是:
+ IF one exists, retrieve the long-term token from `$_COOKIE['FB_LONG_AC_TOKEN']`
+ If it does exist, test to see if it is valid.
+ If valid, use the renew the token and update the cookie if one is returned. (Only one token will be returned per day)
+ Else mark the long-term token as invalid and clear the cookie.
+ Set a `$vaild_user` flag.
+ ELSE IF a new short-term token is available
+ Read the short-term token cookie with the PHP API and exchange this for a long-term token.
+ Store the long-term token in the cookie
+ Clear the short-term token cookie
+ Set a `$valid_user` flag
+ ELSE: The token does not exist or is invalid
+ Redirect the user to the JS API auth dialog and store the returned short term token in a cookie.
+ Reload the page to process this.
+ ENDIF
+ IF `$valid_user`: Do stuff.
Run Code Online (Sandbox Code Playgroud)
您的代码中已经包含了所有部分。您只需要清理逻辑即可使其正常工作。
编辑#2:
我在我的服务器上运行了你的代码。setcookie()它基本上可以工作,但是您输出的调试信息会过早地发送标头,从而抑制设置 cookie的能力。
我通过$out = array();在开头附近声明来运行您的代码,然后将所有的echo和print语句更改为$out[] = "What you were echoing or printing before";“要仍然显示此内容,请echo implode("\n", $out);在<body>文档中添加”。
完成此操作后,我就能够在 cookie 中存储有效令牌,并验证它确实是具有 60 天有效期的长寿命令牌。
| 归档时间: |
|
| 查看次数: |
2971 次 |
| 最近记录: |