├── .gitignore ├── LICENSE ├── README.md ├── composer.json ├── composer.lock └── src ├── InstagramBasicDisplay.php └── InstagramBasicDisplayException.php /.gitignore: -------------------------------------------------------------------------------- 1 | composer.phar 2 | /vendor/ 3 | 4 | # Commit your application's lock file https://getcomposer.org/doc/01-basic-usage.md#commit-your-composer-lock-file-to-version-control 5 | # You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file 6 | # composer.lock 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 espresso.dev 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | *As the Instagram Basic Display API will be deprecated on December 4, 2024 [https://developers.facebook.com/docs/instagram-basic-display-api/](https://developers.facebook.com/docs/instagram-basic-display-api/) this package is no longer maintained. Please use the [Instagram API PHP](https://github.com/espresso-dev/instagram-php) package instead.* 2 | 3 | # Instagram Basic Display PHP API 4 | 5 | A simple PHP wrapper for the Instagram Basic Display API. Based on the [Instagram-PHP-API](https://github.com/cosenary/Instagram-PHP-API) by [Christian Metz](http://metzweb.net) 6 | 7 | [![Latest Stable Version](http://img.shields.io/packagist/v/espresso-dev/instagram-basic-display-php.svg?style=flat)](https://packagist.org/packages/espresso-dev/instagram-basic-display-php) 8 | [![License](https://img.shields.io/packagist/l/espresso-dev/instagram-basic-display-php.svg?style=flat)](https://packagist.org/packages/espresso-dev/instagram-basic-display-php) 9 | [![Total Downloads](http://img.shields.io/packagist/dt/espresso-dev/instagram-basic-display-php.svg?style=flat)](https://packagist.org/packages/espresso-dev/instagram-basic-display-php) 10 | 11 | > [Composer](#installation) package available. 12 | 13 | ## Requirements 14 | 15 | - PHP 5.6 or higher 16 | - cURL 17 | - Facebook Developer Account 18 | - Facebook App 19 | 20 | ## Get started 21 | 22 | To use the [Instagram Basic Display API](https://developers.facebook.com/docs/instagram-basic-display-api), you will need to register a Facebook app and configure Instagram Basic Display. Follow the [getting started guide](https://developers.facebook.com/docs/instagram-basic-display-api/getting-started). 23 | 24 | ### Installation 25 | 26 | I strongly advice using [Composer](https://getcomposer.org) to keep updates as smooth as possible. 27 | 28 | ``` 29 | $ composer require espresso-dev/instagram-basic-display-php 30 | ``` 31 | 32 | ### Initialize the class 33 | 34 | ```php 35 | use EspressoDev\InstagramBasicDisplay\InstagramBasicDisplay; 36 | 37 | $instagram = new InstagramBasicDisplay([ 38 | 'appId' => 'YOUR_APP_ID', 39 | 'appSecret' => 'YOUR_APP_SECRET', 40 | 'redirectUri' => 'YOUR_APP_REDIRECT_URI' 41 | ]); 42 | 43 | echo "Login with Instagram"; 44 | ``` 45 | 46 | ### Authenticate user (OAuth2) 47 | 48 | ```php 49 | // Get the OAuth callback code 50 | $code = $_GET['code']; 51 | 52 | // Get the short lived access token (valid for 1 hour) 53 | $token = $instagram->getOAuthToken($code, true); 54 | 55 | // Exchange this token for a long lived token (valid for 60 days) 56 | $token = $instagram->getLongLivedToken($token, true); 57 | 58 | echo 'Your token is: ' . $token; 59 | ``` 60 | 61 | ### Get user profile 62 | 63 | ```php 64 | // Set user access token 65 | $instagram->setAccessToken($token); 66 | 67 | // Get the users profile 68 | $profile = $instagram->getUserProfile(); 69 | 70 | echo '
';
 71 | print_r($profile);
 72 | echo '
';
 73 | ```
 74 | 
 75 | **All methods return the API data as `json_decode()` - so you can directly access the data.**
 76 | 
 77 | ## Available methods
 78 | 
 79 | ### Setup Instagram
 80 | 
 81 | `new Instagram(/);`
 82 | 
 83 | `array` if you want to perform oAuth:
 84 | 
 85 | ```php
 86 | new InstagramBasicDisplay([
 87 |     'appId' => 'YOUR_APP_ID',
 88 |     'appSecret' => 'YOUR_APP_SECRET',
 89 |     'redirectUri' => 'YOUR_APP_REDIRECT_URI'
 90 | ]);
 91 | ```
 92 | 
 93 | `string` once you have a token and just want to return *read-only* data:
 94 | 
 95 | ```php
 96 | new InstagramBasicDisplay('ACCESS_TOKEN');
 97 | ```
 98 | 
 99 | ### Get login URL
100 | 
101 | `getLoginUrl(, )`
102 | 
103 | ```php
104 | getLoginUrl(
105 |     array(
106 |         'user_profile', 
107 |         'user_media'
108 |     ),
109 |     'state'
110 | );
111 | ```
112 | 
113 | ### Get OAuth token (Short lived valid for 1 hour)
114 | 
115 | `getOAuthToken($code, /)`
116 | 
117 | `true` : Returns only the OAuth token  
118 | `false` *[default]* : Returns OAuth token and profile data of the authenticated user
119 | 
120 | ### Exchange the OAuth token for a Long lived token (valid for 60 days)
121 | 
122 | `getLongLivedToken($token, /)`
123 | 
124 | `true` : Returns only the OAuth token  
125 | `false` *[default]* : Returns OAuth token and profile data of the authenticated user
126 | 
127 | ### Refresh access token for another 60 days before it expires
128 | 
129 | `refreshToken($token, /)`
130 | 
131 | `true` : Returns only the OAuth token  
132 | `false` *[default]* : Returns OAuth token and expiry data of the token
133 | 
134 | ### Set / Get access token
135 | 
136 | - Set the access token, for further method calls: `setAccessToken($token)`
137 | - Get the access token, if you want to store it for later usage: `getAccessToken()`
138 | 
139 | ### User methods
140 | 
141 | **Authenticated methods**
142 | 
143 | - `getUserProfile()`
144 | - `getUserMedia(<$id>, <$limit>)`
145 |     - if an `$id` isn't defined or equals `'me'`, it returns the media of the logged in user
146 | 
147 | ### Media methods
148 | 
149 | **Authenticated methods**
150 | 
151 | - `getMedia($id)`
152 | - `getMediaChildren()`
153 | 
154 | 
155 | ## Pagination
156 | 
157 | The `getUserMedia` endpoint has a maximum range of results, so increasing the `limit` parameter above the limit of 99 won't help.You can use pagination to return more results for this endpoint.
158 | 
159 | Pass an object into the `pagination()` method and receive your next dataset:
160 | 
161 | ```php
162 | $media = $instagram->getUserMedia();
163 | 
164 | $moreMedia = $instagram->pagination($media);
165 | ```
166 | 


--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
 1 | {
 2 |     "name": "espresso-dev/instagram-basic-display-php",
 3 |     "description": "A simple PHP class for accessing the Instagram Basic Display API",
 4 |     "keywords": ["instagram", "api"],
 5 |     "homepage": "https://github.com/espresso-dev/instagram-basic-display-php",
 6 |     "type": "library",
 7 |     "require": {
 8 |         "php": ">=5.6",
 9 |         "ext-curl": "*",
10 |         "ext-json": "*"
11 |     },
12 |     "autoload": {
13 |         "psr-4": {
14 |             "EspressoDev\\InstagramBasicDisplay\\": "src/"
15 |         }
16 |     },
17 |     "license": "MIT",
18 |     "authors": [
19 |         {
20 |             "name": "Herman Schutte",
21 |             "email": "herman@espresso.dev"
22 |         }
23 |     ],
24 |     "minimum-stability": "dev"
25 | }
26 | 


--------------------------------------------------------------------------------
/composer.lock:
--------------------------------------------------------------------------------
 1 | {
 2 |     "_readme": [
 3 |         "This file locks the dependencies of your project to a known state",
 4 |         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
 5 |         "This file is @generated automatically"
 6 |     ],
 7 |     "content-hash": "ca16009b9b2cfa015991077776e95f47",
 8 |     "packages": [],
 9 |     "packages-dev": [],
10 |     "aliases": [],
11 |     "minimum-stability": "dev",
12 |     "stability-flags": [],
13 |     "prefer-stable": false,
14 |     "prefer-lowest": false,
15 |     "platform": {
16 |         "php": ">=5.6",
17 |         "ext-curl": "*"
18 |     },
19 |     "platform-dev": [],
20 |     "plugin-api-version": "1.1.0"
21 | }
22 | 


--------------------------------------------------------------------------------
/src/InstagramBasicDisplay.php:
--------------------------------------------------------------------------------
  1 | setAppId($config['appId']);
 80 |             $this->setAppSecret($config['appSecret']);
 81 |             $this->setRedirectUri($config['redirectUri']);
 82 | 
 83 |             if (isset($config['timeout'])) {
 84 |                 $this->setTimeout($config['timeout']);
 85 |             }
 86 | 
 87 |             if (isset($config['connectTimeout'])) {
 88 |                 $this->setConnectTimeout($config['connectTimeout']);
 89 |             }
 90 |         } elseif (is_string($config)) {
 91 |             // For read-only
 92 |             $this->setAccessToken($config);
 93 |         } else {
 94 |             throw new InstagramBasicDisplayException('Error: __construct() - Configuration data is missing.');
 95 |         }
 96 |     }
 97 | 
 98 |     /**
 99 |      * @param string[] $scopes
100 |      * @param string $state
101 |      * @return string
102 |      * @throws InstagramBasicDisplayException
103 |      */
104 |     public function getLoginUrl($scopes = ['user_profile', 'user_media'], $state = '')
105 |     {
106 |         if (is_array($scopes) && count(array_intersect($scopes, $this->_scopes)) === count($scopes)) {
107 |             return self::API_OAUTH_URL . '?client_id=' . $this->getAppId() . '&redirect_uri=' . urlencode($this->getRedirectUri()) . '&scope=' . implode(',',
108 |                 $scopes) . '&response_type=code' . ($state != '' ? '&state=' . $state : '');
109 |         }
110 | 
111 |         throw new InstagramBasicDisplayException("Error: getLoginUrl() - The parameter isn't an array or invalid scope permissions used.");
112 |     }
113 | 
114 |     /**
115 |      * @param int $id
116 |      * @return object
117 |      * @throws InstagramBasicDisplayException
118 |      */
119 |     public function getUserProfile($id = 0)
120 |     {
121 |         if ($id === 0) {
122 |             $id = 'me';
123 |         }
124 | 
125 |         return $this->_makeCall($id, ['fields' => $this->_userFields]);
126 |     }
127 | 
128 |     /**
129 |      * @param string $id
130 |      * @param int $limit
131 |      * @param string|null $before
132 |      * @param string|null $after
133 |      * @return object
134 |      * @throws InstagramBasicDisplayException
135 |      */
136 |     public function getUserMedia($id = 'me', $limit = 0, $before = null, $after = null)
137 |     {
138 |         $params = [
139 |             'fields' => $this->_mediaFields
140 |         ];
141 | 
142 |         if ($limit > 0) {
143 |             $params['limit'] = $limit;
144 |         }
145 |         if (isset($before)) {
146 |             $params['before'] = $before;
147 |         }
148 |         if (isset($after)) {
149 |             $params['after'] = $after;
150 |         }
151 | 
152 |         return $this->_makeCall($id . '/media', $params);
153 |     }
154 | 
155 |     /**
156 |      * @param string $id
157 |      * @return object
158 |      * @throws InstagramBasicDisplayException
159 |      */
160 |     public function getMedia($id)
161 |     {
162 |         return $this->_makeCall($id, ['fields' => $this->_mediaFields]);
163 |     }
164 | 
165 |     /**
166 |      * @param string $id
167 |      * @return object
168 |      * @throws InstagramBasicDisplayException
169 |      */
170 |     public function getMediaChildren($id)
171 |     {
172 |         return $this->_makeCall($id . '/children', ['fields' => $this->_mediaChildrenFields]);
173 |     }
174 | 
175 |     /**
176 |      * @param object $obj
177 |      * @return object|null
178 |      * @throws InstagramBasicDisplayException
179 |      */
180 |     public function pagination($obj)
181 |     {
182 |         if (is_object($obj) && !is_null($obj->paging)) {
183 |             if (!isset($obj->paging->next)) {
184 |                 return null;
185 |             }
186 | 
187 |             $apiCall = explode('?', $obj->paging->next);
188 | 
189 |             if (count($apiCall) < 2) {
190 |                 return null;
191 |             }
192 | 
193 |             $function = str_replace(self::API_URL, '', $apiCall[0]);
194 |             parse_str($apiCall[1], $params);
195 | 
196 |             // No need to include access token as this will be handled by _makeCall
197 |             unset($params['access_token']);
198 | 
199 |             return $this->_makeCall($function, $params);
200 |         }
201 | 
202 |         throw new InstagramBasicDisplayException("Error: pagination() | This method doesn't support pagination.");
203 |     }
204 | 
205 |     /**
206 |      * @param string $code
207 |      * @param bool $tokenOnly
208 |      * @return object|string
209 |      * @throws InstagramBasicDisplayException
210 |      */
211 |     public function getOAuthToken($code, $tokenOnly = false)
212 |     {
213 |         $apiData = array(
214 |             'client_id' => $this->getAppId(),
215 |             'client_secret' => $this->getAppSecret(),
216 |             'grant_type' => 'authorization_code',
217 |             'redirect_uri' => $this->getRedirectUri(),
218 |             'code' => $code
219 |         );
220 | 
221 |         $result = $this->_makeOAuthCall(self::API_OAUTH_TOKEN_URL, $apiData);
222 | 
223 |         return !$tokenOnly ? $result : $result->access_token;
224 |     }
225 | 
226 |     /**
227 |      * @param string $token
228 |      * @param bool $tokenOnly
229 |      * @return object|string
230 |      * @throws InstagramBasicDisplayException
231 |      */
232 |     public function getLongLivedToken($token, $tokenOnly = false)
233 |     {
234 |         $apiData = array(
235 |             'client_secret' => $this->getAppSecret(),
236 |             'grant_type' => 'ig_exchange_token',
237 |             'access_token' => $token
238 |         );
239 | 
240 |         $result = $this->_makeOAuthCall(self::API_TOKEN_EXCHANGE_URL, $apiData, 'GET');
241 | 
242 |         return !$tokenOnly ? $result : $result->access_token;
243 |     }
244 | 
245 |     /**
246 |      * @param string $token
247 |      * @param bool $tokenOnly
248 |      * @return object|string
249 |      * @throws InstagramBasicDisplayException
250 |      */
251 |     public function refreshToken($token, $tokenOnly = false)
252 |     {
253 |         $apiData = array(
254 |             'grant_type' => 'ig_refresh_token',
255 |             'access_token' => $token
256 |         );
257 | 
258 |         $result = $this->_makeOAuthCall(self::API_TOKEN_REFRESH_URL, $apiData, 'GET');
259 | 
260 |         return !$tokenOnly ? $result : $result->access_token;
261 |     }
262 | 
263 |     /**
264 |      * @param string $function
265 |      * @param string[]|null $params
266 |      * @param string $method
267 |      * @return object
268 |      * @throws InstagramBasicDisplayException
269 |      */
270 |     protected function _makeCall($function, $params = null, $method = 'GET')
271 |     {
272 |         if (!isset($this->_accesstoken)) {
273 |             throw new InstagramBasicDisplayException("Error: _makeCall() | $function - This method requires an authenticated users access token.");
274 |         }
275 | 
276 |         $authMethod = '?access_token=' . $this->getAccessToken();
277 | 
278 |         $paramString = null;
279 | 
280 |         if (isset($params) && is_array($params)) {
281 |             $paramString = '&' . http_build_query($params);
282 |         }
283 | 
284 |         $apiCall = self::API_URL . $function . $authMethod . (('GET' === $method) ? $paramString : null);
285 | 
286 |         $headerData = array('Accept: application/json');
287 | 
288 |         $ch = curl_init();
289 |         curl_setopt($ch, CURLOPT_URL, $apiCall);
290 |         curl_setopt($ch, CURLOPT_HTTPHEADER, $headerData);
291 |         curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, $this->_connectTimeout);
292 |         curl_setopt($ch, CURLOPT_TIMEOUT_MS, $this->_timeout);
293 |         curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
294 |         curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
295 |         curl_setopt($ch, CURLOPT_HEADER, true);
296 | 
297 |         $jsonData = curl_exec($ch);
298 | 
299 |         if (!$jsonData) {
300 |             throw new InstagramBasicDisplayException('Error: _makeCall() - cURL error: ' . curl_error($ch), curl_errno($ch));
301 |         }
302 | 
303 |         list($headerContent, $jsonData) = explode("\r\n\r\n", $jsonData, 2);
304 | 
305 |         curl_close($ch);
306 | 
307 |         return json_decode($jsonData);
308 |     }
309 | 
310 |     /**
311 |      * @param string $apiHost
312 |      * @param string[] $params
313 |      * @param string $method
314 |      * @return object
315 |      * @throws InstagramBasicDisplayException
316 |      */
317 |     private function _makeOAuthCall($apiHost, $params, $method = 'POST')
318 |     {
319 |         $paramString = null;
320 | 
321 |         if (isset($params) && is_array($params)) {
322 |             $paramString = '?' . http_build_query($params);
323 |         }
324 | 
325 |         $apiCall = $apiHost . (('GET' === $method) ? $paramString : null);
326 | 
327 |         $ch = curl_init();
328 |         curl_setopt($ch, CURLOPT_URL, $apiCall);
329 |         curl_setopt($ch, CURLOPT_HTTPHEADER, array('Accept: application/json'));
330 |         curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
331 |         curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
332 |         curl_setopt($ch, CURLOPT_TIMEOUT_MS, $this->_timeout);
333 | 
334 |         if ($method === 'POST') {
335 |             curl_setopt($ch, CURLOPT_POST, count($params));
336 |             curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));
337 |         }
338 | 
339 |         $jsonData = curl_exec($ch);
340 | 
341 |         if (!$jsonData) {
342 |             throw new InstagramBasicDisplayException('Error: _makeOAuthCall() - cURL error: ' . curl_error($ch));
343 |         }
344 | 
345 |         curl_close($ch);
346 | 
347 |         return json_decode($jsonData);
348 |     }
349 | 
350 |     /**
351 |      * @param string $token
352 |      */
353 |     public function setAccessToken($token)
354 |     {
355 |         $this->_accesstoken = $token;
356 |     }
357 | 
358 |     /**
359 |      * @return string
360 |      */
361 |     public function getAccessToken()
362 |     {
363 |         return $this->_accesstoken;
364 |     }
365 | 
366 |     /**
367 |      * @param string $appId
368 |      */
369 |     public function setAppId($appId)
370 |     {
371 |         $this->_appId = $appId;
372 |     }
373 | 
374 |     /**
375 |      * @return string
376 |      */
377 |     public function getAppId()
378 |     {
379 |         return $this->_appId;
380 |     }
381 | 
382 |     /**
383 |      * @param string $appSecret
384 |      */
385 |     public function setAppSecret($appSecret)
386 |     {
387 |         $this->_appSecret = $appSecret;
388 |     }
389 | 
390 |     /**
391 |      * @return string
392 |      */
393 |     public function getAppSecret()
394 |     {
395 |         return $this->_appSecret;
396 |     }
397 | 
398 |     /**
399 |      * @param string $redirectUri
400 |      */
401 |     public function setRedirectUri($redirectUri)
402 |     {
403 |         $this->_redirectUri = $redirectUri;
404 |     }
405 | 
406 |     /**
407 |      * @return string
408 |      */
409 |     public function getRedirectUri()
410 |     {
411 |         return $this->_redirectUri;
412 |     }
413 | 
414 |     /**
415 |      * @param string $fields
416 |      */
417 |     public function setUserFields($fields)
418 |     {
419 |         $this->_userFields = $fields;
420 |     }
421 | 
422 |     /**
423 |      * @param string $fields
424 |      */
425 |     public function setMediaFields($fields)
426 |     {
427 |         $this->_mediaFields = $fields;
428 |     }
429 | 
430 |     /**
431 |      * @param string $fields
432 |      */
433 |     public function setMediaChildrenFields($fields)
434 |     {
435 |         $this->_mediaChildrenFields = $fields;
436 |     }
437 | 
438 |     /**
439 |      * @param int $timeout
440 |      */
441 |     public function setTimeout($timeout)
442 |     {
443 |         $this->_timeout = $timeout;
444 |     }
445 | 
446 |     /**
447 |      * @param int $connectTimeout
448 |      */
449 |     public function setConnectTimeout($connectTimeout)
450 |     {
451 |         $this->_connectTimeout = $connectTimeout;
452 |     }
453 | }
454 | 


--------------------------------------------------------------------------------
/src/InstagramBasicDisplayException.php:
--------------------------------------------------------------------------------
1 |