Mise en place d'une application Facebook avec ZendFramework 1.12 website avec facebook login - Zend Framework 1.12 partie 9

Mise en place d'une application PHP/JS Facebook avec ZendFramework 1.12 website avec login facebook API.

Publié le 02/10/2013

1 - Création de l'application à l'adresse suivante

Vous aurez besoin d'avoir un compte facebook developper, il vous sera possible de créer un compte à partir de cette adresse :

https://developers.facebook.com

Champs requis :

  • - Display Name > nom de l'app
  • - Namespace > espace de nommage de l'app
  • - Adresse électronique de contact
  • - AppDomains > domaine du site

Sélectionnez comment votre application est intégrée à Facebook :

- Website with facebook login ou onglet Page.

Si vous avez sélectionnez "Onglet Page", vous devrez ajouter l'application à la page. Pour ce faire, déclencher cette url avec vos données en paramètres :


http://www.facebook.com/dialog/pagetab?app_id=YOUR_APP_ID&next=YOUR_URL
YOUR_APP_ID : app id fourni dans les paramètres dv fb
YOUR_URL : url de l'app (ex xl : http://www.gerardchic.com/gerardchic_fb_app/)

Source : http://developers.facebook.com/docs/appsonfacebook/pagetabs/

2 - Mise en place du fichier channel.html

Nous allons créer un fichier channel.html à la racine du dossier public de notre application.

Celui-ci contient la variable de langue pour la boite de dialogue facebook connect.


<?php
    $cache_expire = 60*60*24*365;
    header("Pragma: public");
    header("Cache-Control: max-age=".$cache_expire);
    header('Expires: ' . gmdate('D, d M Y H:i:s', time()+$cache_expire) . ' GMT');
?>
<script src="//connect.facebook.net/fr_FR/all.js"></script>

3 - Stockage des infos de l'app fb dans la Zend_Registry

Nous allons stocker les variables de notre application facebook dans l'espace Zend_Registry. Pour ce faire nous allons éditer le fichier /APP/application/config/application.ini comme suit :

Dans la section production, ajouter :


; FB app config fbApp.id = "APP_ID"
fbApp.secret = "FB_SECRET"
fbApp.fileUpload = false

Nous allons ensuite définir ces données dans la methode initConfig() du bootstrap :


protected function _initConfig()
{
    // get Application Config File
    $config = new Zend_Config($this->getOptions());

    // set fb app values
    Zend_Registry::set("fbAppId", $config->fbApp->id);
    Zend_Registry::set("fbAppSecret", $config->fbApp->secret);
}

4 - Mise en place du Facebook JS SDK

Nous allons mettre en place l'init du facebook js sdk dans le layout du module front de notre app. Ce dernier ce placera juste après la balise body du document :


<div id="fb-root"></div>
<script>
//alert('line 1 - t1');
var is_fb_init = false;
var fb_on_ready_callback = null;
window.fbAsyncInit = function()
{
    //alert('line 2 - t3');
    var params =
    {
        appId : '<?php echo Zend_Registry::get("fbAppId"); ?>',
        status : false,
        cookie : true,
        oauth : true,
        xfbml : true
    };
    if($.browser.msie)
        params.channelUrl = 'http://dev.gerardchic.com/public/channel.html';
    FB.init(params);
    FB.getLoginStatus(function(r)
    {
        //alert('line 3 - t4');
        if(r)
        {
            //alert('line 4 - t5 ');
            is_fb_init = true;
            if(fb_on_ready_callback)
                fb_on_ready_callback();
            FB.Canvas.setSize();
        }
    });
    FB.Canvas.setAutoGrow();
};
(function() {
    //alert('line 5 - t2');
    var e = document.createElement('script');
    e.src = document.location.protocol + '//connect.facebook.net/fr_FR/all.js';
    e.async = true;
    document.getElementById('fb-root').appendChild(e);
}());

    // Vérifie si le fb sdk est bien initialisé
    if(is_fb_init)
        fb_ready();
    else
        fb_on_ready_callback = fb_ready;
</script>

Pour rendre notre layout plus propre nous allons mettre ce script dans une vue partielle.

Nous allons créer un fichier fb_login.phtml dans /APP/application/default/views/scripts/common/ avec ce contenu.

Maintenant nous allons pouvoir appeler ce script dans notre layout avec ce code :

<?php echo $this->partial('/common/fb_login.phtml'); ?> 

Pour vérifier si le sdk est bien initialisé, nous allons décommenter les alert dans le script js dans le fichier fb_login.pthml. Attention à vos autres scripts js qui peuvent rentrer en conflit avec l'init du sdk. Je vous recommande désactiver vos autres scripts. Assurer vous aussi de bien avoir une librairie jQuery sans bug avec le sdk. Ici j'ai utilisé la version 1.8.1 de jQuery.

Important : Si votre fb app comporte des invitations, ne pas oublier de configurer la route zend pour l'invitation request.

5 - Mise en place du facebook connect

Nous allons créer un fichier fb_login.js que nous allons lier à notre layout front qui contiendra le code suivant :


// fb init js sdk
function fb_ready()
{
    // all start here...

    // listener fb login
    $('.fb_login').live('click',fblogin);

}

function fblogin()
{
    // login call api
    FB.login(function(response)
    {
        if(response.authResponse)
        {
            // call ajax
            $.ajax({

                // param ajax
                type : "POST",
                url : "/loginfb/",
                data : {accessToken : response.authResponse.accessToken},
                success : function(data){

                    // inject php answer in body, data containing the rendered view
                    $('body').html(data);

                },
                error : function(request, type){

                    // message
                    var message = "Une erreur inconnue est survenue, merci de recharger la page.";
                }
            });
        }
        else
        {
            // message
            var message = "L'autorisation est nécessaire pour l'analyse de votre page.";
        }
    }, {scope: 'email,manage_pages,read_insights,publish_stream'});

}

Cette call ajax déclenchera la méthode loginfbAction() du controller IndexController de notre module default.

6 - Mise en place du Facebook PHP SDK

Nous allons récupérer les fichiers du sdk php > https://github.com/facebook/facebook-php-sdk. Ensuite créer un dossier Facebook dans le dossier library de l'app zf et copier les fichiers suivants :

  • - base_facebook.php
  • - facebook.php
  • - fb_ca_chain_bundle.cr

Maintenant nous allons ajouter un require de la classe FB PHP SDK dans le front controller. Dans le fichier /APP/public/index.php, après le require de Zend_Application.php, ajouter :

// Include FB Lib PHP SDK require_once("Facebook/facebook.php"); 

Récupération des var de l'app fb et affectation à l'objet FB du PHP SDK :

- Ajout dans la methode init() du fichier /APP/application/modules/default/controller/ des lignes suivantes :


// set timezone date_default_timezone_set('Europe/Paris');
// set var facebook parameters $this->facebook = Zend_Registry::get("facebook");

7 - Ajout de méthodes utilitaires dans le model de l'app

On va ensuite ajouter les méthodes utilitaires pour dialoguer avec l'api facebook. Dans la librairy de notre app zf /APP/library/App/Model/, nous allons créer une classe Fbtools pour ces méthodes :


class Zgchic_Model_Fbtools
{
    // FUNCTIONS
    
    /**
    *
    * @param string $access_token : the FB user access token
    * @return string $access_token : the FB user extended access token
    */
    static function extendToken($access_token)
    {
        $graph_url  = "https://graph.facebook.com/oauth/access_token?client_id=" . Zend_Registry::get('fbAppId') . "&client_secret=" . Zend_Registry::get('fbAppSecret') . "&grant_type=fb_exchange_token&fb_exchange_token=" . $access_token;

        $response = self::curl_get_file_contents($graph_url);

        $access_token = json_decode($response);

        if(isset($access_token->error))
        {
            die("0|Oauth");
        }
        else
        {
            $explode = preg_split('/[=&]/',$response);
            return $explode[1];
        }
    }    
    /**
    * Curl Request
    *
    * @param $url
    * @return mixed|string
    */
    static function curl_get_file_contents( $url )
    {
        $c = curl_init();
        curl_setopt( $c, CURLOPT_RETURNTRANSFER, 1 );
        curl_setopt( $c, CURLOPT_SSL_VERIFYPEER, false );
        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";
    }
    
    /**
    * Parse Facebook page signed request
    *
    * @param String $signed_request Facebook Signed Request
    * @param String $secret Facebook App Secret Key
    * @return Array Facebook Page Informations
    */
    static function parse_signed_request( $signed_request, $secret )
    {
        list( $encoded_sig, $payload ) = explode( '.', $signed_request, 2 );
    
        // decode the data
        $sig = self::base64_url_decode( $encoded_sig );
        $data = json_decode(self::base64_url_decode( $payload ), true);
    
        if( strtoupper( $data['algorithm'] ) !== 'HMAC-SHA256' ):
            error_log('Unknown algorithm. Expected HMAC-SHA256');
        return null;
        endif;
    
        // check sig
        $expected_sig = hash_hmac( 'sha256', $payload, $secret, $raw = true );
        if ( $sig !== $expected_sig ) :
            error_log( 'Bad Signed JSON signature!' );
        return null;
        endif;
        return $data;
    }
    
    /**
    * Decode Base64 URL
    *
    * @param String $input encoded data
    * @return String $data decoded data
    */
    static function base64_url_decode($input)
    {
        return base64_decode(strtr($input, '-_', '+/'));
    }
}

8 - Appel de données de facebook dans notre application

Ajouter une méthode de call api social graph dans le controller index de notre module front

Vérifier de bien respecter les principes suivants dans les controllers Action :

  • - appel à l'api fb (call api) seulement si user authentifié.
  • - toujours récupérer l'access token avant une call api fb.

Exemple de méthode call api :

Nous créons d'abord une vue pour la méthode /APP/application/modules/default/views/scripts/index/login.phtml qui va contenir le code suivant :

<?php echo $this->data; ?> 

Et enfin on va pouvoir ajouter dans le ControllerIndex la méthode qui appelera les données de facebook.


public function fbloginAction()
{
    try
    {
        // FB LOGIN ACTION

        // deactivate layout for ajax loading
        $this->_helper->layout->disableLayout();

        // FB PHP SDK init
        // init facebook php sdk

        // prepare fb config array
        $facebookConfig = array(
            'appId' => 'Zend_Registry::get("fbAppId")',
            'secret' => 'Zend_Registry::get("fbAppSecret")',
            'fileUpload' => false
        );

        // create fb object
        $facebook = new Facebook( $facebookConfig );

        // receptionne l'accessToken puis on etend l'access token pour qu'il dure 60 jours
        $accessToken = $this->getRequest()->getPost("accessToken", null);
        $extendedAccessToken = Zgchic_Model_Fbtools::extendToken($accessToken);


        // Set a new access token extend, by first getting it via means other than the SDK
        $facebook->setAccessToken($extendedAccessToken);

        // CALL API FB USER

        // retrieve user's data
        $fbuser = $facebook->api('/me','GET');

        Zend_Debug::dump($fbuser);
    }
    catch(Exception $e)
    {
        $this->view->error = $e->getMessage();
    }
}

On va créer la route dans le fichier /APP/application/configs/application.ini en ajoutant le code suivant :


; Routes - front - fb login
resources.router.routes.loginfb.route = /loginfb
resources.router.routes.loginfb.defaults.module = default
resources.router.routes.loginfb.defaults.controller = index
resources.router.routes.loginfb.defaults.action = loginfb