2012-05-30 5 views
7

保存されたロングライフアクセストークンを使用しようとしていますが、2時間後にグラフAPIから以下のエラーが発生します。私はFacebookにユーザーを送るためのコードを書いて、アクセストークンの交換が可能な新しいコードを手に入れました。これは、後続のすべてのページリクエストで発生することを除いてうまくいきます。Facebookは、そのアクセストークンがサーバーによって返されているにもかかわらずFacebookのPHP/JS SDKセッションが長い時間トークンで期限切れになった

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

完全なテストページの例を以下に示します。明白な理由のために私のキーを省略します。ページにアクセスし、ログインしてから数時間放置してもう一度ページをヒットします(あなたは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> 

私は間違っていますか?これはFacebookの問題ですか?

UPDATE:

私はまだ同じ問題を抱えていますが@cpilkoによって投稿の流れを追跡するために自分のコードを更新しました。私はちょうどいいからログインできます。しかし、数時間後にテストページにアクセスした場合、翌日には、指定されたロングライフアクセストークン(FB JS SDKは接続していると思っていますが、サーバーは認識しませんでした)私はサーバーとFB JS SDKの両方でログインしていると表示されています。私がfacebookから取得した長寿命のトークンは、オリジナルのものと同じです(クッキーに保存されています)。私が理解していないのは、初めて長寿命トークンを使用できない理由です。以下のコードを更新しました。

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

で非常に簡単にグラフの呼び出しを行うことができますAlso-

は、あなたの個人アカウントでアプリを削除して再インストールしようとしてきましたか? –

答えて

4

元のトークンの有効期限が切れたときに、ループ内で動けなくなる理由は、あなたのコードは、Facebookはあなたに新しいトークンを与えることを許可されていないです。 OAuthエラーが発生すると、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! 

それは私のコードだったら、私は2つを使用したいです変数:$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. 

:ページのロードの

EDIT

あなたのワークフローがあることが必要です。あなたはそれを動作させるためにロジックをクリーンアップする必要があります。

編集#2:

私は自分のサーバー上でコードを実行しました。ほとんどの場合は動作しますが、デバッグ情報はヘッダーを早めに送信しているため、setcookie()がCookieを設定することができません。

私は、まだあなたの文書の<body>echo implode("\n", $out);を追加し、これを表示するには$out[] = "What you were echoing or printing before";にすべてのechoprintステートメントを変更することで、先頭近く$out = array();を宣言することによって実行するようにコードを得ました。

これを実行すると、有効なトークンをクッキーに格納することができました。validateは、有効期限が60日間の長寿命トークンです。

日時:デスクトップアプリ:

+0

リダイレクトは、満了したトークンを処理するためのFacebookの文書化された方法によるものです。 http://developers.facebook.com/blog/post/2011/05/13/how-to--handle-expired-access-tokens/ – Gcoop

+0

はい、これは片道です。 JS SDK http://developers.facebook.com/blog/post/534/を使用して、コード内のユーザーを再認証するための別の文書化された方法があります。私がコメントアウトしたメソッドは、あなたのコードに更新するトークンを与えません。 – cpilko

+0

これは以前のコードでしたが、ページが読み込まれ、2時間後にユーザーがウェブサイトにアクセスするたびにjsがリロードして(ユーザーに自動ログインするとき)上記は、ページの半分が読み込まれてから再読み込みされることなく、ユーザーのサーバー側に自動ログインするソリューションに見えました。 – Gcoop

0

はFBのように見えるが、長いトークンのためのサーバー・交流をやってから私たちをdissuadingされる「しかし、へのユーザのログインをせずに長寿命のユーザaccess_tokenはを取得する方法はありませんあなたアプリをもう一度。 https://developers.facebook.com/roadmap/offline-access-removal/

サーバーのタイムゾーン設定を確認しましたか?私はリフレッシュしてoffline_accessトークンをセットアップしましたが、ユーザーがリフレッシュ(自動ではなく)を再度クリックする必要がありました。あなたは

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