2
\$\begingroup\$

Here's an example script I wrote for Instagram (Facebook)'s Basic Display API. I did this for myself because I haven't used Instagram's API since their Legacy API was disabled, and I needed to familiarize myself for upcoming projects. It's super easy to understand and is meant for learning purposes. It covers every function (I think). I would love a critique.

define('client_id', 'your client id here');
define('client_secret', 'your client secret here');
define('redirect_uri', 'your Redirect URI here');

if (isset($_GET['code'])) {
    try{
        #gets code
        $code = $_GET['code'];
        echo '<pre>'.$code.'</pre>';

        #gets short lived access token
        $authorize = get_short_lived_access_token($code);
        echo '<pre>'.$authorize.'</pre>';
        $result = json_decode($authorize);
        $short_lived_access_token = $result->access_token;
        $user_id = $result->user_id;

        #exchanges short lived access token for long lived access token
        $access_token = get_long_lived_access_token($short_lived_access_token, $user_id);
        $result = json_decode($access_token);
        echo '<pre>'.$access_token.'</pre>';
        $long_lived_access_token = $result->access_token;

        #gets user data
        $user = get_user_data($long_lived_access_token, $user_id);
        echo '<pre>'.$user.'</pre>';

        #gets a list of all media
        $media = get_user_media_id($long_lived_access_token, $user_id);
        echo '<pre>'.$media.'</pre>';

        #gets each media entry
        $media = json_decode($media);
        $i = 0;
        foreach($media->data as $media_data){
            $media_id = $media_data->id;
            $media_child = get_user_media_data($long_lived_access_token, $user_id, $media_id);
            echo '<pre>'.$media_child.'</pre>';
            $media_child = json_decode($media_child);
            echo '<img src="'.$media_child->media_url.'"><br><br>';
            if (++$i == 5) break;
        }

        #refreshes access token
        $refresh = refresh_access_token($long_lived_access_token);
        echo '<pre>'.$refresh.'</pre>';

    }catch (Exception $e){
    echo json_encode(array('response'=>'error','message'=>$e->getMessage()));
    }
}else{
    echo 'instagram not connected<br>';
}

echo '<a href="https://api.instagram.com/oauth/authorize?client_id='.client_id.'&redirect_uri='.redirect_uri.'&scope=user_profile,user_media&response_type=code" target="_blank">connect your instagram</a>';

function get_short_lived_access_token($code){
    $url = 'https://api.instagram.com/oauth/access_token';
    $data = array(
                'client_id'     => client_id,
                'client_secret' => client_secret,
                'grant_type'    => 'authorization_code',
                'redirect_uri'  => redirect_uri,
                'code'          => $code
            );
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_POST, true);    
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    $result = curl_exec($ch);
    curl_close($ch);
    return $result;
}

function get_long_lived_access_token($access_token, $user_id){
    $url = 'https://graph.instagram.com/access_token/?';
    $data = array(
                'client_secret' => client_secret,
                'access_token'  => $access_token,
                'grant_type'    => 'ig_exchange_token'
            );
    $string = http_build_query($data);
    $ch = curl_init($url.$string);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    $result = curl_exec($ch);
    curl_close($ch);
    return $result;
}

function get_user_data($access_token, $user_id){
    $url = 'https://graph.instagram.com/'.$user_id.'/?';
    $data = array(
                'access_token'  => $access_token,
                'fields'        => 'username,account_type,media_count'
            );
    $string = http_build_query($data);
    $ch = curl_init($url.$string);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    $result = curl_exec($ch);
    curl_close($ch);
    return ($result);
}

function get_user_media_id($access_token, $user_id){
    $url = 'https://graph.instagram.com/'.$user_id.'/media/?';
    $data = array(
                'access_token'  => $access_token,
                'fields'        => 'id,timestamp'
            );
    $string = http_build_query($data);
    $ch = curl_init($url.$string);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    $result = curl_exec($ch);
    curl_close($ch);
    return ($result);
}

function get_user_media_data($access_token, $user_id, $media_id){
    $url = 'https://graph.instagram.com/'.$media_id.'/?';
    $data = array(
                'access_token'  => $access_token,
                'fields'        => 'caption,id,media_type,media_url,permalink,thumbnail_url,timestamp'
            );
    $string = http_build_query($data);
    $ch = curl_init($url.$string);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    $result = curl_exec($ch);
    curl_close($ch);
    return ($result);
}

function refresh_access_token($access_token){
    $url = 'https://graph.instagram.com/refresh_access_token/?';
    $data = array(
                'access_token'  => $access_token,
                'grant_type'    => 'ig_refresh_token'
            );
    $string = http_build_query($data);
    $ch = curl_init($url.$string);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    $result = curl_exec($ch);
    curl_close($ch);
    return ($result);
}
\$\endgroup\$
4
  • 1
    \$\begingroup\$ your post helped me a lot. I am trying to get the user profile after signing in. I was wondering if you came across something like this when integrating Basic Display API : stackoverflow.com/questions/74049080/… \$\endgroup\$ Commented Oct 13, 2022 at 0:58
  • 1
    \$\begingroup\$ @TharakaNirmana looks like you got your answer! Let me know if you ned any further assistance. \$\endgroup\$
    – tony
    Commented Oct 14, 2022 at 1:11
  • \$\begingroup\$ I have a question related to refreshing the access token. FB has mentioned Refresh a long-lived Instagram User Access Token that is at least 24 hours old but has not expired. Refreshed tokens are valid for 60 days from the date at which they are refreshed. In your code snippet, the access token is not saved in the database and there is no cron job setup found to refresh the access token after 24 hours or a few days before it expires. I would like to know if any action is required or if it will work without setting them up (database & cron job). \$\endgroup\$
    – Frank
    Commented Oct 18, 2022 at 13:23
  • \$\begingroup\$ @Frank If you know you need it longer than 24hrs why wait until it's about to expire to renew? In my code snippet I assume that I need the access token for as long as possible, hence why I exchange the short lived access token for the long lived one immediately. \$\endgroup\$
    – tony
    Commented Oct 19, 2022 at 21:24

1 Answer 1

1
\$\begingroup\$

Overall feedback

It might be wise to put all the functions and constants into a class for the sake of encapsulation. That way the constants can be namespaced. Perhaps it would be wise to have a constant for the base URLs - for example:

const API_URL = 'https://api.instagram.com';
const GRAPH_URL = 'https://graph.instagram.com';

There is a bit of redundancy between the functions. It might be wise to have a function that handles the cURL functions - perhaps accepting a URL or path that can be appended to a base URL (e.g. defined using const as https://graph.instagram.com/) if the URL does contain a TLD, a parameter for the data, and an optional parameter for method - which would handle CURLOPT_POST.

It is advisable to follow recommended standards - e.g. the PHP Standards Recommendations - especially PSR-1 and PSR-12.

The try/catch looks like something Your Common Sense critiqued in an earlier review as being "a cargo cult code that makes no sense". Do any of the functions called within the try block throw exceptions? I could understand it being used if the calls to json_decode() passed JSON_THROW_ON_ERROR as the $flags parameter...

Targeted feedback

Constant format

As is a common convention with many Object oriented languages, PSR-1 recommends constants be declared in all caps:

Class constants MUST be declared in all upper case with underscore separators. 1

Thus it would be simpler to spot CLIENT_ID as a constant compared to client_id, and similar for the other two constants.

Array format

There isn't anything wrong with using array() but as of the time of writing, PHP has Active support for versions 8.0 and 7.4, and since PHP 5.4 arrays can be declared with short array syntax (PHP 5.4) - i.e. [].

Return early

After the three define lines there is this code:

if (isset($_GET['code'])) {
    try{
        #gets code

and at the end of that block is this:

}else{
    echo 'instagram not connected<br>';
}

If the code was put into a function and the logic is flipped so that the scenario where the query string doesn't contain a code is handled first, the subsequent indentation levels can be decreased:

if (!isset($_GET['code'])) {
    return 'instagram not connected<br>';
}
try {
    #gets code

This can improve readability as anyone reading the code would have less of a need to scroll horizontally.

Iteration counter with foreach

Instead of this foreach that manually maintains $i:

   $i = 0;
   foreach($media->data as $media_data){

with the last step:

        if (++$i == 5) break;

Use this format:

foreach ($media->data as $i => $media_data) {

And the last step:

    if ($i === 5) break;

While it isn't wrong to update $i manually, it can be handled by the iteration.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.