2011-04-29 57 views
0

我有以下腳本可用,即如果用戶尚未登錄,它會轉到Facebook登錄頁面,並詢問他們是否可以在應用上發佈消息牆:僅在需要時纔要求facebook權限

<?php 
    require 'facebook.php'; 

    $facebook = new Facebook(array(
     'appId' => 'removed for security reasons', 
     'secret' => 'removed for security reasons', 
     'cookie' => true, 
    )); 

    $session = $facebook->getSession(); 

    if ($session) { 

     if (isset($_GET[id])) { 

      $post = $facebook->api("/" . $_GET['id'] . "/feed", "POST", array('message' => 'Hello!')); 
      echo 'A message has been posted on your friends wall'; 

     } else { 

      $friends = $facebook->api('/me/friends'); 

      foreach ($friends as $key=>$value) { 
       echo 'You have ' . count($value) . ' friends<br />'; 

       foreach ($value as $fkey=>$fvalue) { 
        echo 'friend id = ' . $fvalue[id] . ' - friend name = ' . $fvalue[name] . ' - <a href="/stage2.php?id=' . $fvalue[id] . '">post message</a><br />'; 
       } 
      } 
     } 

    } else { 

     $loginUrl = $facebook->getLoginUrl(array(
      'req_perms' => 'publish_stream', 
      'next' => 'http://'.$_SERVER['SERVER_NAME'].'/stage1.php', 
      'cancel_url' => 'http://'.$_SERVER['SERVER_NAME'].'/cancel.php', 
     )); 

     header('Location: '.$loginUrl); 
    } 
?> 

這是如何改善,所以它不要求在開始的擴展權限。它應該只要求基本權限來顯示朋友列表,並且只有在用戶點擊朋友發佈消息時才請求擴展權限。

+0

從我可以告訴,你沒有要求stage1中的publish_stream。當你到達stage2時,有一個有效的會話,重定向從不執行。 – DannyKK 2011-04-29 12:58:29

+0

好的,但是你發佈的代碼永遠不會要求發佈流的權限。您可以使用FQL查找您的應用程序是否具有所需的權限。 – DannyKK 2011-04-29 13:20:29

回答

0

很快,有件事我想指出,關於以下代碼塊:

foreach ($friends as $key=>$value) { 
    echo 'You have ' . count($value) . ' friends<br />'; 

    foreach ($value as $fkey=>$fvalue) { 
     echo 'friend id = ' . $fvalue[id] . ' - friend name = ' . $fvalue[name] . ' - <a href="/stage2.php?id=' . $fvalue[id] . '">post message</a><br />'; 
    } 
} 

你的第一個foreach循環是非常誤導,不是好的做法的。 Graph API在呈現數據的方式上並不太一致,但是您做這些foreach的原因是要處理返回的JSON對象中的data鍵。這通常是一個壞主意,因爲data密鑰通常與其他密鑰一起存在(如paging)。相反,我會檢查看看$friends['data']是否爲空,然後重新指定$friends數組,如下所示:$friends = $friends['data'];

例子:

if (!empty($friends['data'])) 
{ 
    $friends = $friends['data']; 
} 
else 
{ 
    $friends = array(); 
} 

現在,你的問題。

你提到你不想過度要求權限。這是一件好事,但問題在於Facebook不會輕易檢查您擁有或不擁有的權限。有一個FQL表格,可以讓你檢查你的用戶是否擁有一定的權限,但是這張表沒有得到任何緊急的更新。如果您從用戶獲得額外權限(或者用戶撤消權限),然後您檢查此FQL表以瞭解權限的狀態,則可以(也可能會)讀取不正確的值,並且您將獲得誤報。

你有三種選擇來解決這個問題,我可以從頭腦中想到。

  1. 繼續您的stage1.php代碼,就像您一樣 - 您在那裏獲得安裝和用戶會話的方式沒有任何問題。每次用戶加載頁面時,您都會更改第2頁以通過OAuth端點重定向您的用戶,請求發佈流權限。 OAuth端點不會重新提示用戶進行安裝,並將在途中發送。

    這種做法的缺點是,每個發佈到朋友牆上的請求都會變成3個請求。

    • 初始頁面加載
    • 的OAuth的重定向/負載
    • 從OAuth的重定向回您的應用程序

    這種方法還要求您在添加一個標誌,你next關鍵的loginURL,您可以查找它以確保用戶通過OAuth端點,否則您將遇到無限重定向錯誤。使用FB Javascript SDK檢查用戶當前的權限集。爲此,您將使用FB.getLoginStatus方法。

    例子:

    <div id="fb-root"></div> 
    <script src="http://code.jquery.com/jquery-1.5.2.min.js" 
        type="text/javascript" charset="utf-8"> 
    </script> 
    <script src="http://connect.facebook.net/en_US/all.js" 
        type="text/javascript" charset="utf-8"> 
    </script> 
    <script type="text/javascript"> 
    (function($) 
    { 
        FB.init({ 
         appId: '<?= FB_APP_ID; ?>', 
         cookie: true, 
         status: true, 
         xfbml: true 
        }); 
    
        $('a').click(function(event) 
        { 
         var self = this; 
    
         event.preventDefault(); 
    
         FB.getLoginStatus(function(session) 
         { 
          if (session.perms.match(/\"publish_stream\"/)) 
          { 
           /* This user has publish stream, so we don't need 
           * to ask again 
           **/ 
           window.location = $(self).attr('href'); 
          } 
          else 
          { 
           /* This user does not have publish stream, so we need 
           * to ask. 
           **/ 
           FB.login(function(response) 
           { 
            if (response && response.perms.match(/publish_stream/)) 
            { 
             /* We now have publish stream access! */ 
             window.location = $(self).attr('href'); 
            } 
           }, { 
            perms: 'publish_stream' 
           }); 
          } 
         }) 
    
         return false; 
        }) 
    })(jQuery); 
    
  2. 不要使用任何擴展權限,使用JavaScript SDK(再次),併爲用戶提供一個發佈,對話,因爲他們想在壁上發佈的每個用戶。這也是一件相對容易的事情。

    例子:

    給您的用戶鏈接:

    <a href="#" data-id="123">Friend 1</a> 
    <a href="#" data-id="456">Friend 2</a> 
    <a href="#" data-id="789">Friend 3</a> 
    

    你可以做這樣的事情:

    <div id="fb-root"></div> 
    <script src="http://code.jquery.com/jquery-1.5.2.min.js" 
        type="text/javascript" charset="utf-8"> 
    </script> 
    <script src="http://connect.facebook.net/en_US/all.js" 
        type="text/javascript" charset="utf-8"> 
    </script> 
    <script type="text/javascript"> 
    (function($) 
    { 
        $('a').click(function(event) 
        { 
         var user_id = $(this).data('id'); 
    
         FB.ui({ 
          method: 'feed', 
          message: 'Hello!', 
          to:   user_id 
         }, function(response) 
         { 
          //this gets called whether it was successful, or not. 
         }) 
        }); 
    
    })(jQuery); 
    
+0

你會如何重寫foreach循環部分? – oshirowanen 2011-04-29 15:44:17

+0

而不是foreach($ friends爲$ key => $ value)我只是這樣做的,如果(!empty($ friends)){$ friends = $ friends ['data']; } else {/ * friends is empty * /} – 2011-04-29 18:35:03

1

這是你的代碼的改寫,與我認爲是最佳實踐:

<?php 
require 'facebook.php'; 

$facebook = new Facebook(array(
    'appId' => 'removed for security reasons', 
    'secret' => 'removed for security reasons', 
    'cookie' => true, 
)); 

$session = $facebook->getSession(); 
// Prepare the login url with the right permission 
$loginUrl = $facebook->getLoginUrl(array(
    'req_perms' => 'publish_stream', 
    'next' => 'http://'.$_SERVER['SERVER_NAME'].'/stage1.php', 
    'cancel_url' => 'http://'.$_SERVER['SERVER_NAME'].'/cancel.php', 
)); 

if ($session) { 
    try { 
     // Before processing the request 
     // check if we got the right permission 
     $perms = $facebook->api(array(
      "method" => "fql.query", 
      "query"  => "SELECT publish_stream FROM permissions WHERE uid=me()" 
     )); 
     if($perms[0]['publish_stream']==='1') { 
      // We have the right permission 
      if (isset($_GET['id'])) { 
       // A small security measure 
       $id = (int) $_GET['id']; 
       $post = $facebook->api("/$id/feed", "POST", array('message' => 'Hello!')); 
       echo 'A message has been posted on your friends wall'; 
      } else { 
       $friends = $facebook->api(array(
        "method" => "fql.query", 
        "query"  => "SELECT uid,name FROM user WHERE uid IN (SELECT uid2 FROM friend WHERE uid1=me())" 
       )); 
       foreach($friends as $friend) 
        echo "friend id = {$friend['uid']} - friend name = {$friend['name']} - <a href=\"/stage2.php?id={$friend['uid']}\">post message</a><br />"; 
      } 
     } else { 
      // We don't have the right permission 
      header('Location: '.$loginUrl); 
     } 
    } catch (FacebookApiException $e) { 
     error_log($e); 
    } 
} else { 
    header('Location: '.$loginUrl); 
} 
?> 

如何檢查權限解釋爲here。此外,我添加了評論,以節省編寫解釋。

+0

關於FQL權限表的publish_stream權限請求不會以任何(合理的)速度更新。獲得此權限並在相同的5分鐘窗口內進行檢查不會產生準確的用戶給予您的權限的響應。我昨天測試了這一點,因爲我需要檢查用戶的權限。另外,如上所述,他不想要求他不需要的權限(例如,用戶不一定要通過他的應用程序在他們的朋友的牆上發帖) – 2011-04-29 18:42:20

+0

@JimR:如果我理解他的問題是正確的,stage2只有當用戶將**發佈到他朋友的牆上時纔可以訪問。所以*當OP需要獲得此許可時,這是*。 – ifaour 2011-04-29 22:02:17

+0

至於'權限'表,它可能需要時間來實際驗證我們的檢查,現在這是一個很好的觀點。我從來沒有嘗試過檢查響應速度,但我認爲需要一段時間才能傳播到所有FB服務器。如果是這種情況,那麼OP可能不會檢查權限,而是*捕獲錯誤號。如果它匹配「你沒有權限..等等」錯誤沒有。然後==>請求權限! – ifaour 2011-04-29 22:09:18