Запрашивать разрешения facebook только при необходимости

#facebook #facebook-graph-api #facebook-php-sdk

#Facebook #facebook-graph-api #facebook-php-sdk

Вопрос:

У меня есть следующий скрипт, который работает, т. Е. он переходит на страницу входа 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);
    }
?>
  

Как это можно улучшить, чтобы при запуске не запрашивались расширенные разрешения. Он должен запрашивать только базовые разрешения для отображения списка друзей и запрашивать расширенные разрешения только в том случае, если пользователь нажимает на друга, чтобы опубликовать сообщение.

Комментарии:

1. Из того, что я могу сказать, вы не запрашиваете publish_stream на stage1. Когда вы переходите к этапу 2, существует допустимый сеанс, и перенаправление никогда не выполняется.

2. Ну да, но опубликованный вами код никогда не будет запрашивать разрешение на публикацию потока. Вы можете использовать FQL, чтобы определить, имеет ли ваше приложение требуемые разрешения.

Ответ №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);
}
?>
  

Как проверить наличие разрешения, объясняется здесь. Также я добавил комментарии, чтобы сэкономить на написании объяснения.

Комментарии:

1. Запрос разрешения publish_stream из таблицы разрешений FQL не обновляется с какой-либо (разумной) скоростью. Получение этого разрешения и проверка его в течение одного и того же 5-минутного окна не дает точного ответа относительно того, какие разрешения предоставил вам ваш пользователь. Я тестировал это только вчера, так как мне нужно было проверить разрешения пользователей. Кроме того, как он заявил выше, он не хочет запрашивать разрешения, которые ему не нужны (например, пользователь не обязательно хочет размещать сообщения на стене своих друзей через его приложение)

2. @JimR: Если я правильно понял его вопрос, этап2 доступен только тогда, когда пользователь собирается опубликовать сообщение на стене своего друга. Итак, это тот случай, когда OP должен запросить это разрешение.

3. Что касается permission таблицы, и для фактического подтверждения нашей проверки может потребоваться время, теперь это хороший момент. Я никогда не пробовал проверять скорость ответа, но я бы предположил, что для распространения на все серверы FB потребуется некоторое время. Если это так, то OP может не проверять наличие разрешения и вместо этого перехватить ошибку no. и если это соответствует ошибке «у вас нет разрешения .. etc», нет. затем ==> запрашивать разрешение!

Ответ №2:

Вкратце, я хочу кое-что отметить относительно следующего блока кода:

 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 />';
    }
}
  

Ваш 1-й цикл foreach действительно вводит в заблуждение и вообще не является хорошей практикой. Graph API не слишком последователен в том, как он представляет данные, но причина, по которой вы выполняете foreach, заключается в том, чтобы иметь дело с data ключом в возвращаемом объекте JSON. Как правило, это плохая идея, потому что этот 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, в противном случае вы получите ошибку бесконечного перенаправления.

  2. Используйте FB Javascript SDK для проверки текущего набора разрешений ваших пользователей. Для этого вы будете использовать метод FB.getLoginStatus.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 amp;amp; response.perms.match(/publish_stream/))
                        {
                            /* We now have publish stream access! */
                            window.location = $(self).attr('href');
                        }
                    }, {
                        perms: 'publish_stream'
                    });
                }
            })
    
            return false;
        })
    })(jQuery);
      
  3. Не используйте никаких расширенных разрешений, используйте 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);
      

Комментарии:

1. Как бы вы переписали раздел цикла foreach?

2. Вместо foreach($ friends как $key=> $value) Я бы просто сделал, if (!empty($ friends)) { $friends = $friends[‘data’]; } остальное { /* друзья пусто */ }