仅在需要时才要求facebook权限

问题描述:

我有以下脚本可用,即如果用户尚未登录,它会转到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

很快,有件事我想指出,关于以下代码块:

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

这是你的代码的改写,与我认为是最佳实践:

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