post_ico4

Integracja serwisu z Facebookiem po raz kolejny

O integracji z Facebookiem pisałem już nie raz. Od mojego ostatniego wpisu na ten temat (maj 2014) trochę się pozmieniało. Ze względu na sporą popularność poprzedniego wpisu (według GA) postanowiłem odświeżyć temat.

No to zaczynamy

Na wstępie utwórz aplikację na Facebooku. Żeby to zrobić twoje konto musi być zweryfikowane. Jak już potwierdzisz, ze ty to naprawdę ty ;) przejdź na stronę deweloperską i kliknij Create new App. Wyskoczy standardowe okienko, gdzie wpisuje się nazwę aplikacji. Następnie przechodzimy do bardziej szczegółowej edycji.

facebook-developers

Identyfikator aplikacji oraz App Secret będą potrzebne przy konfigurowaniu biblioteki, dane te nie powinny wpaść w niepowołane ręce – aplikacja będzie gromadziła w końcu dane osobowe.

Z zakładek znajdujących się z lewej strony wybierz Ustawienia i kliknij + Dodaj platformę. Z okienka wybierz „Strona internetowa”. Następnie wpisz adres URL do skryptu, w którym znajdzie się logowanie z Facebookiem. Istnieje możliwość logowania się z różnych podstron serwisu. W tym celu należy podać listę domen w polu App domains.

facebook-developers-ustawienia

Integrowanie z naszym serwisem

Dla potrzeb stron www Facebook udostępnia JavaScript SDK oraz PHP SDK. Ja omówię wykorzystanie PHP SDK, który można pobrać stąd.

Przed czytaniem dalszej części pobierz cały kod. Większość plików pochodzi z Composer i SDK, a więc skupie się tylko na 3 plikach napisanych przeze mnie.

src/FacebookApi.php

<?php
namespace LukaszSocha\DemoFB;

/**
 * Class FacebookApi
 * @package LukaszSocha\DemoFB
 * @author Łukasz Socha <kontakt@lukasz-socha.pl>
 * @licence http://opensource.org/licenses/bsd-license.php
 */
class FacebookApi{
    /**
     * @var string ID aplikacji
     */
    private $appId;
    /**
     * @var string Klucz secret do aplikacji
     */
    private $secret;
    /**
     * @var Facebook API
     */
    private $fbSdk;
    /**
     * @var array Lista praw dostępu. Pełna lista dostępna tutaj https://developers.facebook.com/docs/facebook-login/permissions
     */
    private $permissions=array();
    /**
     * @var string Adres URL na jaki przekieruje po zalogowaniu
     */
    private $callback;

    /**
     * @param string $appId
     * @param string $secret
     */
    public function __construct($appId, $secret)
    {
        $this->appId = $appId;
        $this->secret = $secret;
        $this->fbSdk=new \Facebook\Facebook(array('app_id' => $this->appId, 'app_secret' => $this->secret));
    }

    /**
     * @param array $permissions
     */
    public function setPermissions($permissions)
    {
        $this->permissions = $permissions;
    }

    /**
     * @param string $callback
     */
    public function setCallback($callback)
    {
        $this->callback = $callback;
    }

    /**
     * Zwraca access token, jeżeli istnieje
     * @return bool|string
     */
    public function getAccessToken() {
        if(!empty($_SESSION['facebook_access_token'])) {
            return $_SESSION['facebook_access_token'];
        }
        return false;
    }

    /**
     * Pobiera access token zalogowanego użytkownika
     * @return bool
     */
    public function login() {
        $helper = $this->fbSdk->getRedirectLoginHelper();
        try {
            $accessToken = $helper->getAccessToken();
        } catch(\Facebook\Exceptions\FacebookSDKException $e) {
            // There was an error communicating with Graph
            echo $e->getMessage();
            exit;
        }

        if (isset($accessToken)) {
            $_SESSION['facebook_access_token'] = (string) $accessToken;
            echo 'Successfully logged in!';
            exit;
        } elseif ($helper->getError()) {
            var_dump($helper->getError());
            var_dump($helper->getErrorCode());
            var_dump($helper->getErrorReason());
            var_dump($helper->getErrorDescription());
            exit;
        }
    }

    /**
     * Zwraca adres URL do zalogowania
     * @return string adres URL
     */
    public function getLoginUrl() {
        $helper = $this->fbSdk->getRedirectLoginHelper();
        return $helper->getLoginUrl($this->callback, $this->permissions);
    }

    /**
     * Zwraca tablicę z danymi użytkownika
     * @param string $param Informacje jakie mają byc pobrane z Facebooka
     * @return array Dane użytkownika
     */
    public function getUserData($param) {
        return $this->fbSdk->get($param, $this->getAccessToken());
    }
}

Facebook co jakiś czas aktualizuje API. Dlatego postanowiłem tym razem zamknąć wszystko w swojej klasie. Będzie łatwiej zaktualizować kod w razie nowych wersji API.

index.php

<?php
session_start();
$loader = include "vendor/autoload.php";
$fb = new \LukaszSocha\DemoFB\FacebookApi('appId', 'appSecret');
$fb->setPermissions(array('email', 'public_profile'));
$fb->setCallback('http://adres-url/after-login.php');

if ($fb->getAccessToken()) {
    // jeżeli zalogowany wyświetli danr
    $data = $fb->getUserData('me?fields=email, name');
    print_r($data->getDecodedBody());
} else {
    // jeżeli niezalogowany
    echo '<a href="' . $fb->getLoginUrl() . '">Zaloguj</a>';
}

W linii 3 ustawiam ID aplikacji oraz klucz secret. Niżej przekazuję do obiektu tablicę z uprawnieniami aplikacji. W linii 6 przekazuję adres URL do skryptu logowania.

If zaczynający się od linii 8 wyświetla dane użytkownika (o ile się zalogował) lub link do logowania. Metoda getDecodedBody() zwraca tablicę, więc przetworzenie danych (np. podczas logowania do serwisu www) nie jest problematyczne.

after-login.php

<?php
session_start();
$loader = include "vendor/autoload.php";
$fb = new \LukaszSocha\DemoFB\FacebookApi('appId', 'appSecret');
$fb->login();

W pliku tym wywołuję metodę login() z mojej klasy. W przypadku pomyślnego logowania metoda zapisuje do sesji access token dzięki, któremu można pobierać dane użytkownika.

Będę aktualizować wpis jak tylko zorientuję się, że Facebook znowu coś zmienia :). Liczę też na waszą czujność i informację w komentarzu.

Co sądzisz o wpisie?
BeżnadziejnySłabyŚredniDobryBardzo dobry (4 głosów, średnia ocen: 4,50 z 5)
Loading...
  • dsa

    (maj 3014) back to future ?

    • Sebastian Zaborowski

      Martin i Delorian na facebooku :D

      • Nie takie rzeczy czasem programista musi potrafić zrobić :D

  • Michał Wierzba

    Mnie wyskakuje Parse error: syntax error, unexpected ‚[‚ in
    vendor/facebook/php-sdk-v4/src/Facebook/Facebook.php
    on line 125, co radzisz?

    • Ta wersja SDK wymaga PHP co najmniej w wersji 5.4. Poprzednie wersje PHP nie posiadają składni tablicy typu $array = […]

      • Michał Wierzba

        Dzięki ogarnąłem to po dłuższej chwili ale zapomniałem edytować wpisu :(

  • Paweł

    mod_fcgid: stderr: PHP Fatal error: require_once(): Failed opening required ‚/home/polis/domains/polisonline.pl/public_html/beta/files/class/fb/vendor/composer/ClassLoader.php’ (include_path=’.:/usr/local/php56/lib/php’) in /home/polis/domains/polisonline.pl/public_html/beta/files/class/fb/vendor/composer/autoload_real.php on line 12

    Do tego biała strona i błąd generuje ta linijka: $fb->setCallback(‚http://adres-url/after-login.php’);
    Co można z tym zrobić? MI się skończyły pomysły w raz z grzebaniem w plikach samego SDK.

    • Napisz na forum.php.pl. Może już ktoś miał taki problem.

      • Paweł

        $fb = new LukaszSochaDemoFBFacebookApi(‚appId’, ‚appSecret’);

        Czy w tej linijce oprócz appID i appSecret należy coś zmienić?
        Może głupie pytanie ale właśnie tego nie chce otworzyć.

        • Wystarczy podać id i secret key. W chwili pisania artykułu wszystko działało.

  • Udało Ci się rozwiązać problem?

  • Dawid Krupiarz

    Ogarnąłeś wylogowywanie?

  • Witam, jestem ciężko niezorientowany: jak się loguję to przenosi mnie na stronę after_login.php a mym oczom ukazuje się ”Successfully logged in!” Jak mam przekierować to z powrotem na główną?

    • Musisz w metodzie login(), w pliku FacebookApi.php wykonać to co jest potrzebne w twojej aplikacji. Jeżeli chcesz tylko przekierować to funkcja header(„Location: ….”);

      • Jest mały problem z „headers already send”, ale ok mogę zostać na after-login.php, nie jest to w sumie wielki problem. Mam za to inny problem :”Cross-site request forgery validation failed. The „state” param from the URL and session do not match.” – jak zrobię include powyższego pliku index do innej podstrony i próbuję się zalogować. Ido tego z adresu bez „www” działa w 50%przypadków, a z adresem z „www.” nigdy. Dodam że w ustawieniach aplikacji na fb dodane mam oba adresy. Jak to okiełznać?

        • Musi być coś wysyłane do przeglądarki przed wywołaniem funkcji header(). Nie może być nawet znaku nowej linii.

          • A faktycznie leciało echo ‚zalogowany’; . Usunąłem to echo i w htaccess zrobiłem przekierowanie wywołań bez www na http://www.adresstrony i poszło. Dziękuję bardzo za pomoc, sam bym się z tym grzebał z tydzień. Pozdrawiam

  • jeszcze takie małe pytanie: facebook zwraca mi name bez polskich znaków, np. zamiast ł mam ??. Dodam, że strona ma utf-8. Ustawia się to gdzieś?

    • Nie miałem nigdy teo typu problemów. Najprawdopodobniej jest coś nie tak z kodowaniem strony / pliku.

  • Mariusz Lipiński

    Czyzby znowu przestalo dzialac?

    • Ostatnio nie miałem okazji nic robić pod Facebooka, więc nie wiem czy znowu coś zmieniali.

  • w PHP7 wyświetla ERROR 500

  • Hans von Mahalitz

    Ech masakra. Może jakieś podpowiedzi odnośnie dzielenia sesji między JS a PHP? U mnie oczywiście jak pojadę kodem z przykładu https://developers.facebook.com/docs/php/howto/example_access_token_from_javascript to mam „This authorization code has been used.”…

    • Nie używałem JS SDK, więc niestety w tym nie pomogę.