2012-05-30 2 views
7

Ich versuche ein gespeichertes Long-Life Access Token zu verwenden, aber nach 2 Stunden bekomme ich den untenstehenden Fehler von der Graph API. Ich habe einen Code geschrieben, um den Benutzer an Facebook zu senden, um einen neuen Code zu erhalten, der gegen ein Zugriffstoken ausgetauscht werden kann. Das funktioniert einwandfrei, außer dass dies bei jeder folgenden Seitenanfrage geschieht. Facebook setzt weiterhin mein Zugriffs-Token mit dem folgenden Fehler außer Kraft. obwohl dieses Zugriffstoken von ihrem Server zurückgegeben wird.Facebook PHP/JS SDK "Session ist zur Unix-Zeit abgelaufen" mit Long Life Token

Error validating access token: Session has expired at unix time 1338300000. The current unix time is 1338369365. 

Das vollständige Beispiel der Testseite finden Sie weiter unten. Meine Schlüssel aus offensichtlichen Gründen weglassen. Drücken Sie die Seite, loggen Sie sich ein und lassen Sie sie für ein paar Stunden und drücken Sie die Seite erneut (Sie erhalten die Umleitung zu Facebook und zurück mit dem Code in der URL), laden Sie die Seite neu und es wird weiter nach Facebook und zurück umgeleitet , Ereignis, obwohl ich es sage, das Zugangstoken zu benutzen, das es gerade für besagten Code zurückgebracht hat.

<?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> 

Was mache ich falsch? oder das ist ein Problem mit Facebook?

UPDATE:

Ich habe meinen Code aktualisiert, um den Fluss von @cpilko geschrieben folgen jedoch bin ich immer noch das gleiche Problem. Ich kann mich ein- und ausloggen. Wenn ich jedoch die Testseite nach einigen Stunden besuche, sage ich am nächsten Tag, dass ich die Session expired-Ausnahme mit dem mitgelieferten langlebigen Zugriffstoken bekomme (FB JS SDK denkt, dass ich verbunden bin, aber der Server nicht), aktualisiere ich die Seite und Ich werde sowohl vom Server als auch vom FB JS SDK als eingeloggt angezeigt und der Long Life Token, den ich von Facebook bekomme, ist der gleiche wie der, den ich ursprünglich ausprobiert habe (gespeichert in meinen Cookies). Was ich nicht verstehe, ist, warum ich das Langzeit-Token nicht zum ersten Mal benutzen kann. Aktualisierter Code unten.

<?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> 
+0

haben Sie versucht, die App in Ihrem persönlichen Konto zu entfernen und neu zu installieren? –

Antwort

4

Der Grund, warum Sie in der Schleife stecken, wenn Ihr Original-Token Code abgelaufen ist nicht Facebook Sie ist damit ein neues Token geben. Wenn Sie einen OAuth-Fehler erhalten, rufen Sie das OAuth-Dialogfeld auf, das Ihr Cookie nicht mit einem neuen Token auffüllt.

Das andere Problem, das Sie haben, ist Sie zum langfristigen Zugriffstoken mit Ihrer kurzfristigen Zugriffstoken zu überschreiben, bevor Sie einen api Anruf:

// 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! 

Wenn es mein Code ist, hat ich zwei verwenden würde, Variablen: $access_token_temp und $access_token_long nur so konnte ich die Dinge gerade halten.

EDIT

Ihr Workflow beim Laden der Seite muss sein:

+ 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. 

Sie alle Teile in Ihrem Code haben. Sie müssen nur die Logik aufräumen, damit es funktioniert.

Edit # 2:

lief ich den Code auf meinem Server. Es funktioniert meistens, aber die Debugging-Informationen, die Sie ausgeben, senden Header vorzeitig, was die Fähigkeit von setcookie() blockiert, einen Cookie zu setzen.

ich Ihren Code bekam durch laufen $out = array(); in der Nähe von Anfang an erklärt, dann durch alle echo und print Aussagen $out[] = "What you were echoing or printing before"; ändert dies zu noch angezeigt werden, fügen echo implode("\n", $out); im <body> Ihr Dokument.

Sobald ich das getan habe, war ich in der Lage, ein gültiges Token in einem Cookie zu speichern, und validate, dass es in der Tat ein langlebiges Token mit einem 60-tägigen Ablauf ist.

+0

Die Weiterleitung ist per Facebook dokumentierte Möglichkeit, abgelaufene Tokens zu behandeln. http://developers.facebook.com/blog/post/2011/05/13/how-to-handle-expired-access-tokens/ – Gcoop

+0

Ja, das ist ein Weg. Sie haben eine weitere dokumentierte Möglichkeit, einen Benutzer in Ihrem Code erneut zu authentifizieren, indem Sie das JS SDK http://developers.facebook.com/blog/post/534/ verwenden. Die Methode, die ich auskommentiert habe, gibt deinem Code keinen Token für die Verlängerung. – cpilko

+0

Das war mein vorheriger Code, aber es bewirkt, dass die Seite geladen wird, und dann, wenn die js neu startet (um den Benutzer automatisch einzuloggen), jedes Mal, wenn der Benutzer die Website nach zwei Stunden besucht. Oben schien die Lösung zu sein, sich automatisch auf der Seite des Benutzerservers anzumelden, ohne dass eine Seite halb geladen und dann neu geladen wurde. – Gcoop

0

Sieht aus wie FB ist uns zu tun, Server-Börsen für längere Token abzubringen:

Re: Desktop-Anwendungen: „Allerdings gibt es keine Möglichkeit, einen langlebigen Benutzer access_token zu erhalten, ohne auf die Benutzeranmeldung mit Ihrem App noch einmal. " https://developers.facebook.com/roadmap/offline-access-removal/

Haben Sie die Zeitzoneneinstellungen auf Ihrem Server überprüft? Ich habe offline_access-Token mit einer Aktualisierung eingerichtet - obwohl es Benutzer beteiligt re-click zum Aktualisieren (nicht automatisch).

Auch-du Graph Anrufe tun kann ganz einfach mit

$facebook->api("me"); // no need to add access token, or decode JSON, etc. 
Verwandte Themen