Nous allons mettre en place un login via l'api d'instagram dans une page de notre app ZendFramework 1.12. Cette dernière va appeler des photos de l'utilisateur et les affichera. elle va aussi appeler des photos pour un tag donné et quelques count seront effectué sur le likes et comments pour se faire la main. Dans le tutorial notre applications zf va s'appeler zgchic et vous retrouverez ce préfixe dans les différentes classes présentées. Ce préfixe sera à remplacer par celui défini dans votre application.
Il vous faudra un compte instagram et créer un nouveau client pour notre app zf à l'adresse suivante :
Il vous sera demandé un nom pour notre app et l'adresse du site web ou elle sera appelée :
http://www.domaine.tld
Et l'adresse de redirection une fois que l'authentification a eu lieu. Ici ce sera la route vers notre contrôleur Instagram que allons créer par la suite :
http://www.domaine.tld/instagram
Une fois le client enregistré, Instagram va nous fournir un client id et client secret. Ces informations vont nous servir pour le login.
1 - Création d'un table pour l'enregistrement des utilisateurs instagram
Dans la bdd de notre app zf nous allons créer une table "instagram_users" qui va nous servir à enregistrer le token utilisateur facilitant sa prochaine connexion.
SET NAMES utf8;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for `instagram_users`
-- ----------------------------
DROP TABLE IF EXISTS `instagram_users`;
CREATE TABLE `instagram_users` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`username` varchar(255) NOT NULL,
`user_id` varchar(255) NOT NULL,
`token` varchar(255) NOT NULL,
`created_time` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1;
2 - Mise en place des classes Modèles avec Doctrine
Nous allons déclarer cette nouvelle table dans notre app en créant deux fichiers de Modèle : l'un va contenir la description de la table et l'autre sera la classe où ranger les méthodes afférentes aux opérations CRUD.
Dans /APP/library/Zgchic/Model/BaseInstragramUsers.php :
<?php
// Connection Component Binding
Doctrine_Manager::getInstance()->bindComponent('Zgchic_Model_InstagramUsers', 'doctrine');
/**
* Zgchic_Model_BaseInstagramUsers
*
* This class has been auto-generated by the Doctrine ORM Framework
*
* @property integer $id
* @property string $username
* @property string $user_id
* @property string $token
*
* @package ##PACKAGE##
* @subpackage ##SUBPACKAGE##
* @author ##NAME## <##EMAIL##>
* @version SVN: $Id: Builder.php 7490 2010-03-29 19:53:27Z jwage $
*/
abstract class Zgchic_Model_BaseInstagramUsers extends Doctrine_Record
{
public function setTableDefinition()
{
$this->setTableName('instagram_users');
$this->hasColumn('id', 'integer', 4, array(
'type' => 'integer',
'length' => 4,
'fixed' => false,
'unsigned' => false,
'primary' => true,
'autoincrement' => true,
));
$this->hasColumn('username', 'string', 255, array(
'type' => 'string',
'length' => 255,
'fixed' => false,
'unsigned' => false,
'primary' => false,
'notnull' => true,
'autoincrement' => false,
));
$this->hasColumn('user_id', 'string', 255, array(
'type' => 'string',
'length' => 255,
'fixed' => false,
'unsigned' => false,
'primary' => false,
'notnull' => true,
'autoincrement' => false,
));
$this->hasColumn('token', 'string', 255, array(
'type' => 'string',
'length' => 255,
'fixed' => false,
'unsigned' => false,
'primary' => false,
'notnull' => true,
'autoincrement' => false,
));
$this->hasColumn('created_time', 'timestamp', null, array(
'type' => 'timestamp',
'fixed' => false,
'unsigned' => false,
'primary' => false,
'notnull' => true,
'autoincrement' => false,
));
}
public function setUp()
{
parent::setUp();
}
}
Dans /APP/library/Zgchic/Model/BaseInstragramUsers.php :
<?php
/**
* Zgchic_Model_InstagramUsers
*
* This class has been auto-generated by the Doctrine ORM Framework
*
* @package ##PACKAGE##
* @subpackage ##SUBPACKAGE##
* @author ##NAME## <##EMAIL##>
* @version SVN: $Id: Builder.php 7490 2010-03-29 19:53:27Z jwage $
*/
class Zgchic_Model_InstagramUsers extends Zgchic_Model_BaseInstagramUsers
{
}
3 - Création d'une classe Instagram qui va contenir les méthodes de communication avec l'api
Dans /APP/library/Zgchic/Model/Instagram.php, remplacer les valeurs : CLIENT_ID et CLIENT_SECRET par celle de votre app :
<?php
class Zgchic_Model_Instgram
{
/**
* Post data by curl
* @static
* @param $url
* @param $auth_code
* @return mixed
*/
static function postCurl( $url, $auth_code )
{
// init curl
$ch = curl_init();
// set-up param curl by post
curl_setopt( $ch, CURLOPT_URL, "https://api.instagram.com/oauth/access_token" );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
curl_setopt( $ch, CURLOPT_POST, true );
// set-up post data
$data = array
(
'client_id' => 'CLIENT_ID',
'client_secret' => 'CLIENT_SECRET',
'grant_type' => 'authorization_code',
'redirect_uri' => $url,
'code' => $auth_code
);
// set-up curl form post data
curl_setopt( $ch, CURLOPT_POSTFIELDS, $data );
// execute curl and retrieve answer from instagram
$output = curl_exec( $ch );
// close curl connection
curl_close( $ch );
// json decode
return $output = json_decode( $output );
}
/**
* Get data by curl
* @static
* @param $url
* @return mixed
*/
static function getCurl( $url )
{
// init curl
$ch = curl_init();
// set-up param curl by post
curl_setopt( $ch, CURLOPT_URL, $url );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
// execute curl and retrieve answer from instagram
$output = curl_exec( $ch );
// close curl connection
curl_close( $ch );
return $output = json_decode( $output, true );
}
/**
* Get user id by call api
* @static
* @param $username
* @return string
*/
static function getUserId( $username )
{
$username = strtolower( $username );
$token = "InsertThatHere";
$url = "https://api.instagram.com/v1/users/search?q=".$username."&access_token=".$token;
$get = file_get_contents( $url );
$json = json_decode( $get );
foreach( $json->data as $user )
{
if( $user->username == $username )
return $user->id;
}
return '00000000'; // return this if nothing is found
}
}
4 - Mise en place des routes, du contrôleur et de la vue dans le module front de notre app
En premier lieu nous allons créer les routes dans le fichier /APP/application/configs/application.ini, dans la section production :
; Routes - front - login instagram
resources.router.routes.logininstagram.route = /logininstagram
resources.router.routes.logininstagram.defaults.module = default
resources.router.routes.logininstagram.defaults.controller = index
resources.router.routes.logininstagram.defaults.action = logininstagram
; Routes - front - success instagram
resources.router.routes.instagram.route = /instagram
resources.router.routes.instagram.defaults.module = default
resources.router.routes.instagram.defaults.controller = instagram
resources.router.routes.instagram.defaults.action = index
Ensuite nous allons créer notre contrôleur dans le module front de notre app zf /APP/application/modules/default/controllers/InstagramController.php dans lequel on prendra soin de remplacer les valeurs 'www.domain.tld' par celle de votre application :
<?php
class InstagramController extends Zend_Controller_Action
{
public function init()
{
// set timezone
date_default_timezone_set( 'Europe/Paris' );
}
public function indexAction()
{
try
{
// set layout
$this->_helper->layout->setLayout( 'master' );
// test if user already logged
// auth instagram get code
$auth_code = $_GET['code'];
//Zend_Debug::dump($auth_code);
// retrieve user info
$user_info = Zgchic_Model_Instgram::postCurl( 'http://www.domain.tld/instagram/', $auth_code );
//Zend_Debug::dump($user_info);
// test if answer is correct
if( isset( $user_info->access_token ) )
{
// retrieve access token
$token = $user_info->access_token;
// test if user already exist
if( Doctrine_Core::getTable( 'Zgchic_Model_InstagramUsers' )->findOneByUserId( $user_info->user->id ) === false )
{
// store user in db
$user = new Zgchic_Model_InstagramUsers();
$user->user_id = $user_info->user->id;
$user->username = $user_info->user->username;
$user->token = $user_info->access_token;
$user->created_time = date( 'Y-m-d H:i:s' );
$user->save();
}
// retrieve full user's info
$user_info_full = Zgchic_Model_Instgram::getCurl( 'https://api.instagram.com/v1/users/'.$user_info->user->id.'/?access_token='.$user_info->access_token );
$this->view->user_info_full = $user_info_full['data'];
// retrieve recent media from user and send to the view
$this->view->media = Zgchic_Model_Instgram::getCurl( 'https://api.instagram.com/v1/users/'.$user_info->user->id.'/media/recent/?access_token='.$user_info->access_token );
// calculate total likes, comments and send to view
$total_likes = 0;
$total_comments = 0;
foreach( $this->view->media['data'] as $media )
{
$total_likes += $media['likes']['count'];
$total_comments += $media['comments']['count'];
}
$this->view->total_likes = $total_likes;
$this->view->total_comments = $total_comments;
// retrieve tag and send to the view
$this->view->tag = Zgchic_Model_Instgram::getCurl( 'https://api.instagram.com/v1/tags/TAG/media/recent?access_token='.$user_info->access_token );
}
else
{
header( 'Location:https://api.instagram.com/oauth/authorize/?client_id=CLIENT_ID&redirect_uri=http://www.domain.tld/instagram/&response_type=code&scope=likes+comments' );
}
}
catch(Exception $e)
{
echo $e->getMessage();
}
}
}
Et enfin nous allons créer notre vue :
Dans /APP/application/modules/default/views/scripts/, créer un dossier instagram. Dans ce dossier, créer un fichier index.phtml et y placer le code suivant :
<div id="global">
<h1>media</h1>
<p>total media : <span><? echo $this->user_info_full['counts']['media']; ?></span></p>
<p>followed by : <span><? echo $this->user_info_full['counts']['followed_by']; ?></span></p>
<p>follows : <span><? echo $this->user_info_full['counts']['follows']; ?></span></p>
<p>total likes : <span><? echo $this->total_likes; ?></span></p>
<p>total comments : <span><? echo $this->total_comments; ?></span></p>
<div>
<ul class="thumbnails">
<?php foreach($this->media['data'] as $media): ?>
<li class="span3">
<a href="#" class="thumbnail">
<img src="<?php echo $media['images']['thumbnail']['url']; ?>" alt="150x150" data-src="holder.js/150x150">
</a>
<p>text : <span><?php echo $media['caption']['text']; ?></span></p>
<p> comments : <span><?php echo $media['comments']['count']; ?></span></p>
<h3>tags</h3>
<?php foreach($media['tags'] as $tag): ?>
<span><?php echo $tag; ?></span>
<?php endforeach; ?>
<p>likes : <span><?php echo $media['likes']['count']; ?></span></p>
</li>
<?php endforeach; ?>
</ul>
</div>
<h1>tag</h1>
<div>
<ul class="thumbnails">
<?php foreach($this->tag['data'] as $tag_media): ?>
<li class="span3">
<a href="<?php echo $tag_media['link']; ?>" class="thumbnail">
<img src="<?php echo $tag_media['images']['thumbnail']['url']; ?>" alt="150x150" data-src="holder.js/150x150"/>
</a>
</li>
<?php endforeach; ?>
</ul>
</div>
</div>
On va pouvoir maintenant voir le résultat en testant notre travail.
Pour une intégration digne de ce nom il faut mettre un système de cache avec une durée de vie longue si ce module se retrouve utilisé sur la home d'un site.
Liens utiles :
instagram.com/developer/api-console apigee.com/console/instagram
Exemple url autorisation :
https://instagram.com/oauth/authorize/?client_id=CLIENT_ID&redirect_uri=http://www.domain.tld/authinstagram/&response_type=token http://www.domain.tld/index/authinstagram/#access_token=TOKEN