How to create an Instagram badge on your website using API

Interact with API is quite easy. I did it in PHP.
You can find the Instagram's API documentation here http://instagr.am/developer/.

Let me quickly explain ho to move the first steps with some generic operations, with some user-centered operations and with the realtime system.

STEP 1: Register your application

Like other social networks, also Instagram asks to create an app in order to use the API. You can create your own app here: http://instagr.am/developer/manage/
Once created it gives back an ID and a SECRET.

ID could be used for generic requests that don't involve user relations. In other words, ID could be used when we only need to play with public data, for example when we want to show all public photos shot in a place etc.

SECRET is used to authenticate a user and to parse his data, his contacts etc, in order to give him a custom experience. Obviously the user must grant to our app the access to his data through a standard form provided by Instagram.

STEP 2: Get last photos shot in a determinate location

One of the funniest option is to show last photos shot in a determinate location, in my case at Boca Barranca. To do this authentication is not needed, your ID is enough.
Steps to do are: find the location's id starting from a geographic location, then find photos assigned to that id.

Here the procedure explained step-by-step, at the end the entire source code.

I write the URL in order to find my location

	$url="https://api.instagram.com/v1/locations/search?lat=44.525655&lng=12.278917&distance=1000&client_id=12345;

Where I found it? Obviously in the official documentation.
client_id is the id of your app, you've received it when you've created the app and you can retrieve anytime into the chapter Manage.
distance is the radius of the circle to search inside, expressed in metri.
lat and lng are the latitude and the longitude. How did I found them? Width Google Maps.


I've searched my place, I've clicked on the "link" button  and copied the link, in my case: http://maps.google.it/maps?q=boca+barranca,+ravenna&hl=it&sll=41.426253,4.042968&sspn=27.187351,54.711914&t=v&hq=boca+barranca,&hnear=Ravenna,+Emilia+Romagna&z=11
Do you see sll=? Immediately after there are, comma separated, latitude and longitude.

Setting cURL

Without too much details, I'm going to use cURL to send my request. First of all, the init:

	$ch=curl_init();
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);

The second last line tells to cURL that all SSL certificates must be considered valid. In fact we are working with an encrypted URL, you deduce it because the URL starts with https instead of http, and we must validate the Instagram certificate. There is a way more elegant to accomplish, but for now this easy way it's ok for us.
The last line tells to cURL to return a variable as reply, instead to print it on screen.

Request execution and results parsing

	$response=curl_exec($ch);
curl_close($ch);

Now I've the response inside the var $response. Response is wrote in JSON format, that is a standard data structure. I decode this format to a more usable format: PHP objects.

	$locations=json_decode($response);

Now I only need to look inside my results, search for Boca Barranca and save his ID.

	$locationId=0;
foreach($locations->{'data'}
as $location) {
    if($location->{'name'}=='Boca Barranca')
{
        $locationId=$location->{'id'};
        break;
        }
    }

At the end of this cycle I've the ID of my location in $locationId. If no location are the right one, $locationId will be equal to 0.
If you want to display the entire list of founded locations, simply write
print_r($locations);

All this steps should be done just one time: when you find your location id, just hard-code it in order to reduce the number of API calls and to increase the speed of your script (and for the Instagram's server healthcare, of course!).

Recuperare le immagini recenti della nostra location

Con un'altra chiamata cURL recupero le foto recenti. L'indirizzo da utilizzare l'ho trovato sempre sulla documentazione, dove ci sono spiegate tante altre cose da poter fare in maniera analoga.

	$url="https://api.instagram.com/v1/locations/".$locationId."/media/recent/?&client_id=12345";
$ch=curl_init();
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
$response=curl_exec($ch);
curl_close($ch);
$photos=json_decode($response);

Ora in $photos ho l'elenco di tutte le ultime foto scattate al Boca Barranca. Visualizzo le anteprime a video, linkate all'originale in instagram:

	foreach($photos->{'data'}
as $photo) { ?>
    <a href="<?= $photo->{'link'};
?>"><img src="<?=
$photo->{'images'}->{'thumbnail'}->{'url'}; ?>"
/></a>
    <? }

Avrei potuto fare tante altre cose, utilizzando tutti gli altri campi come i dettagli sull'autore, i commenti alla foto, le dimensioni della foto etc. Tutti i campi sono elencati... nella documentazione ;)

Il codice completo

	$url="https://api.instagram.com/v1/locations/search?lat=44.525655&lng=12.278917&distance=1000&client_id=12345;
$ch=curl_init();
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
$response=curl_exec($ch);
curl_close($ch);

	

$locations=json_decode($response); $locationId=0; foreach($locations->{'data'} as $location) {     if($location->{'name'}=='Boca Barranca') {         $locationId=$location->{'id'};         break;         }     }

$url="https://api.instagram.com/v1/locations/".$locationId."/media/recent/?&client_id=12345"; $ch=curl_init(); curl_setopt($ch,CURLOPT_URL,$url); curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false); curl_setopt($ch,CURLOPT_RETURNTRANSFER,true); $response=curl_exec($ch); curl_close($ch); $photos=json_decode($response);

	foreach($photos->{'data'}
as $photo) { ?>
    <a href="<?= $photo->{'link'};
?>"><img src="<?=
$photo->{'images'}->{'thumbnail'}->{'url'}; ?>"
/></a>
    <? }

PASSO 3: E se ci servisse l'autenticazione?

Come ho scritto prima, per avere a che fare con le relazioni tra utenti occorre essere autenticati. Cioè occorre dire "Io sono Roberto Pasini, fammi vedere Instagram dalla mia prospettiva".
Autenticarsi permette di fornire delle esperienze personalizzate a tutti gli utenti che accetteranno di concedere l'accesso ai propri dati alla nostra applicazione, e cioè si potranno anche compiere azioni a nome loro, come commentare o dare il like a delle foto.

Come si fa? Sempre con delle chiamate, ma questa volta Instagram ci farà rimbalzare su una propria pagina, dove verrà chiesto il permesso dell'utente, e poi tornerà al nostro sito chiedendoci di confermare l'autorizzazione. Solo allora ci restituirà un token, cioè un codice che è valido temporaneamente per effettuare le operazioni desiderate a nome dell'utente.

Vediamo passo a passo, e in fondo tutto il codice.

Imposto i parametri della mia app

	$clientID='12345';
$clientSecret='abcde';
$code=$_REQUEST["code"];
$my_url="http://www.ilmiosito.com/instagram/handler.php";

La variabile $my_url non è altro che l'indirizzo completo del file che state facendo. Instagram farà sempre riferimento a lui.

Chiedo l'autorizzazione dell'utente

	if(empty($code))
{
    $dialog_url="https://api.instagram.com/oauth/authorize/?client_id=".$clientID."&redirect_uri=".urlencode($my_url)."&response_type=code";
    header('Location:
'.$dialog_url);
    die();
    }

In pratica, se non ho già ricevuto un codice da Instagram, redireziono l'utente sulla pagina che gli chiederà il permesso di utilizzare la mia app. Questo permesso verrà chiesto solo la prima volta che l'utente utilizza la app. L'utente può revocarlo in qualsiasi momento dall'elenco delle sue applicazioni.

Ricevuto il permesso, richiedo il token

Faccio l'ennesima chiamata cURL per ricevere il token che mi permetterà di mettermi nei panni dell'utente. La chiamata è di tipo POST, come potete leggere nella documentazione (sempre lei), e quindi devo passare le 5 variabili via POST (questo è il motivo delle ultime due curl_setopt).

	if(!empty($code))
{
    $token_url="https://api.instagram.com/oauth/access_token";
    $fields_string="client_id=".$clientID."&redirect_uri=".urlencode($my_url)."&client_secret=".$clientSecret."&code=".$code."&grant_type=authorization_code";
    $ch=curl_init();
    curl_setopt($ch,CURLOPT_URL,$token_url);
    curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false);
    curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
    curl_setopt($ch,CURLOPT_POST,5);
    curl_setopt($ch,CURLOPT_POSTFIELDS,$fields_string)
    $response=curl_exec($ch);
    curl_close($ch);

	

	$auth=json_decode($response);
    }

Ora, se ho in mano il token, posso fare quello che voglio:

	if(isset($auth->{'access_token'}))
{
    // do what you want
    }

Non avete idea di cosa fare? Beh cercate qualche spunto... sulla documentazione.
Il principio di funzionamento è sempre il solito... chiamate cURL e interpretazione della risposta.

Il codice intero

	$clientID='12345';
$clientSecret='abcde';
$code=$_REQUEST["code"];
$my_url="http://www.ilmiosito.com/instagram/handler.php";

	

if(empty($code)) {     $dialog_url="https://api.instagram.com/oauth/authorize/?client_id=".$clientID."&redirect_uri=".urlencode($my_url)."&response_type=code";     header('Location: '.$dialog_url);     die();

if(!empty($code)) {     $token_url="https://api.instagram.com/oauth/access_token";     $fields_string="client_id=".$clientID."&redirect_uri=".urlencode($my_url)."&client_secret=".$clientSecret."&code=".$code."&grant_type=authorization_code";     $ch=curl_init();     curl_setopt($ch,CURLOPT_URL,$token_url);     curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false);     curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);     curl_setopt($ch,CURLOPT_POST,5);     curl_setopt($ch,CURLOPT_POSTFIELDS,$fields_string)     $response=curl_exec($ch);     curl_close($ch);

    $auth=json_decode($response);     }

	if(isset($auth->{'access_token'}))
{
    // do what you want
    }

PASSO 4: Performance

Fare troppe chiamate alle API può essere lento per il nostro sito, e può sovraccaricare il server di Instagram che, per tutelarsi, se riceve troppe chiamate smette di risponderci.

Ci sono due modi per limitare il numero di chiamate e velocizzare il nostro sito. Io nel sito del Boca Barranca li ho implementati entrambi.

Salvare i dati in locale

Cioè salvare il risultato della chiamata in un database nel proprio server, in modo da leggere i dati in locale senza dover interrogare continuamente il server di Instagram. Cioè voi chiedete una volta ogni tanto i dati a Instagram, tramite lo script visto sopra, vi salvate i risultati e a tutti i vostri utenti potete fornire già i risultati. Poi ogni tanto, tramite cron job o verificando ogni volta la data di ultimo aggiornamento, procedete con un aggiornamento dei dati tramite una nuova richiesta a Instagram.

Questo approccio ha due limiti. Il primo è che può essere usato solo nel caso in cui non forniamo una applicazione user-centered, cioè solo per le operazioni che non richiedono l'autenticazione dell'utente le quali necessitano necessariamente di dati personali diversi da tutti gli altri.
Il secondo è che siamo legati ad un tempo di refresh. Cioè se controlliamo ogni ora la presenza di una nuova foto del Boca Barranca, può darsi che una persona l'abbia scattata alle 21:05 e questa foto non apparirà nel sito fino alle 22:00. In alcuni casi non è un grosso problema, ma nel mio caso mi piacerebbe aggiornare le immagini in tempo reale, così se c'è un concerto nel sito vengono mostrate subito le foto. (poi il Boca è un posto magnifico, c'ha il wi-fi libero e un sacco di gente sempre connessa)
Per queste esigenze hanno inventato il Real-time.

Usare il Realtime

Come ho appena spiegato, il Real-time serve a delegare Instagram dell'aggiornamento delle tue immagini nel sito nel momento in cui qualcosa di nuovo accade.
Per fare questo occorre dire ad Instagram quale genere di evento vogliamo catturare: ad esempio location se vogliamo che aggiorni le nostre foto quando ce ne sono di nuove nella nostra location. Al solito, lo si fa tramite una chiamata cURL alla quale risponderemo con il codice che Instagram ci invia.
Le varie possibilità sono spiegate nella documentazione.

All'inizio del mio file ci metterò questo:

	if(isset($_GET['hub_mode'])&&$_GET['hub_mode']=='subscribe'&&isset($_GET['hub_challenge']))
{
    echo $_GET['hub_challenge'];
    die();
    }

che praticamente, se arriva una richiesta di sottoscrizione al Real-time, lui risponde con il codice di conferma.

La richiesta cURL può essere effettuata attraverso l'API Console, compilando i campi con i valori corretti. Basta farla una volta. Si sceglie, nel mio caso, Subscriptions e poi subscriptions (POST) [Location]. Si preme nell'ingranaggio, si scrive il client_id, il client_secret, si cancella il campo verify_token che non ci serve nel mio caso, poi nel Text si sostituisce {callback URL} con l'URL dello script (lo stesso che prima abbiamo usato su $my_url) e {Location ID you want to subscribe to} lo si sostituisce con l'id della location (che abbiamo trovato prima). Si preme OK. Quindi si preme il tasto POST.

Dovrebbe mostrare il report della chiamata, con la conferma di riuscita o con l'eventuale errore.
Se vi esce l'errore "Unable to reach callback URL" sappiate che questo si verifica sia quando l'indirizzo specificato in $my_url non è corretto e lo script non esiste, sia quando lo script restituisce una pagina vuota, per una qualche ragione. In questo caso, meglio verificarlo di persona andando a controllare col browser che l'URL sia corretto e passandogli delle variabili di test direttamente dall'URL (tanto vuole variabili GET).

Ora, se tutto è andato bene, ogni volta che verrà caricata una nuova foto scattata al Boca, Instagram si occuperà di richiamare il mio script, il quale andrà ad aggiornare il mio database locale di foto facendo l'intera richiesta che abbiamo visto all'inizio.