2012-05-30 13 views
7

Próbuję użyć zapisanego żetonu dostępu o długim czasie życia, ale po 2 godzinach otrzymuję poniższy błąd z interfejsu API wykresu. Napisałem kod, aby wysłać użytkownika do Facebooka, aby uzyskać nowy kod, który można wymienić na token dostępu, który działa dobrze, z wyjątkiem tego, że dzieje się to na każdym kolejnym żądaniu strony, Facebook nadal unieważnia mój token dostępu z poniższym błędem, pomimo tego, że token dostępu jest zwracany przez ich serwer.Facebook PHP/JS SDK "Sesja wygasła w czasie unixowym" z długim tokenem życia

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

Cały przykład strony testowej znajduje się poniżej. Pomijanie kluczy z oczywistych powodów. Uderz w stronę, zaloguj się, a następnie opuść ją na kilka godzin i naciśnij ponownie stronę (otrzymasz przekierowanie na facebooka iz powrotem z kodem w adresie URL), załaduj ponownie stronę i nadal będzie przekierowywać na facebook iz powrotem zdarzenie, chociaż mówię, żeby użył tokenu dostępu, który właśnie zwrócił dla tego kodu.

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

Co robię źle? czy to jest problem z Facebookiem?

UPDATE:

I zostały zaktualizowane mój kod śledzić przepływ zamieszczonych przez @cpilko jednak Ciągle mam ten sam problem. Mogę się zalogować i wymeldować. Jednak jeśli odwiedzę stronę testową po kilku godzinach, powiedzmy następnego dnia, otrzymam wyjątek Sesja wygasła z dostarczonym tokenem o przedłużonej żywotności (FB JS SDK uważa, że ​​jestem połączony, ale serwer nie), odświeżam stronę i Jestem pokazany jako zalogowany przez serwer i FB JS SDK, a długi żeton życia, który otrzymuję z Facebooka, jest taki sam, jak ten, który wypróbowałem oryginalnie (przechowywany w moich plikach cookie). Nie rozumiem, dlaczego po raz pierwszy nie mogę użyć żetonu o długim życiu. Zaktualizowany kod poniżej.

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

próbowałeś usunąć i ponownie zainstalować aplikację w koncie osobistym? –

Odpowiedz

4

Powodem utkniesz w pętli, gdy oryginalny tokenu wygasa jest Twój kod nie pozwala na Facebooku, aby dać Ci nowy token. Gdy pojawi się błąd OAuth, wywołujesz okno dialogowe OAuth, które nie wypełnia ponownie Twojego pliku cookie nowym tokenem.

Innym problemem trzeba się pan nadpisywania długoterminowego tokenu dostępu ze swojej krótkotrwałej tokenu dostępu przed dokonaniem połączenia 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! 

Gdyby to było moje kodu, chciałbym użyć dwóch zmienne: $access_token_temp i $access_token_long po to, aby zachować porządek.

EDIT

przepływ pracy na stronie obciążenia musi być:

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

Masz wszystkie części w kodzie. Musisz tylko oczyścić logikę, aby działała.

Edit # 2:

Pobiegłem swój kod na moim serwerze. W większości działa, ale informacje o debugowaniu, które wypuszczasz, wysyłają przedwcześnie nagłówki, blokując możliwość ustawienia pliku cookie na setcookie().

mam kodu do uruchomienia deklarując $out = array(); blisko początku, a następnie zmieniając wszystkie echo i print sprawozdań do $out[] = "What you were echoing or printing before"; Aby nadal wyświetlać tego dodać echo implode("\n", $out); w <body> dokumentu.

Kiedy to zrobiłem, udało mi się zapisać ważny token w ciasteczku, a validate, że jest to rzeczywiście długi żeton z 60-dniowym okresem ważności.

+0

Przekierowanie jest według udokumentowanego sposobu działania Facebooka w celu obsługi wygasłych tokenów. http://developers.facebook.com/blog/post/2011/05/13/how-to--handle-expired-access-tokens/ – Gcoop

+0

Tak, to jest jeden sposób. Masz kolejny udokumentowany sposób ponownego uwierzytelnienia użytkownika w swoim kodzie za pomocą JS SDK http://developers.facebook.com/blog/post/534/. Metoda, którą wykreśliłem, nie daje Twojemu kodowi tokena do odnowienia. – cpilko

+0

To był mój poprzedni kod, ale powoduje on załadowanie strony, a następnie, gdy js kopie w reload (aby automatycznie zalogować użytkownika) za każdym razem, gdy użytkownik odwiedza stronę po dwóch godzinach. Wydawało się, że powyższe rozwiązanie polega na automatycznym zalogowaniu się po stronie serwera użytkownika, bez konieczności wczytywania strony, a następnie przeładowania. – Gcoop

0

Wygląda na FB jest odwieść nas od robienia serwera wymiany dla dłuższych tokeny:

Re: aplikacji komputerowych: „Niestety, nie ma sposobu, aby uzyskać długi żywot access_token użytkownika bez konieczności logowania użytkownika do ponownie aplikację. " https://developers.facebook.com/roadmap/offline-access-removal/

Czy sprawdziłeś ustawienia strefy czasowej na swoim serwerze? Mam ustawione tokeny offline_access, z odświeżaniem - chociaż wymagało to ponownego kliknięcia przez użytkowników, aby odświeżyć (nie automatycznie).

Również-można zrobić połączeń wykresu dość łatwo

$facebook->api("me"); // no need to add access token, or decode JSON, etc. 
Powiązane problemy