mkhab7/php-instagram-graph

A modern PHP 8.4 SDK for Instagram Graph API with comprehensive features and clean architecture

v1.0.0 2025-08-10 16:46 UTC

This package is auto-updated.

Last update: 2025-09-02 10:16:49 UTC


README

Latest Version PHP Version Tests Code Coverage License

A modern, comprehensive PHP 8.4+ SDK for the Instagram Graph API with clean architecture, full type safety, and extensive feature coverage.

โœจ Features

  • ๐Ÿš€ Modern PHP 8.4 - Leverages latest PHP features: typed properties, attributes, enums, match expressions, named arguments
  • ๐Ÿ—๏ธ Clean Architecture - SOLID principles, dependency injection, service-oriented design
  • ๐Ÿ” Complete Authentication - OAuth 2.0 flow, token management, automatic refresh
  • ๐Ÿ“Š Full API Coverage - Users, Media, Comments, Messaging, Insights, Webhooks
  • ๐Ÿ›ก๏ธ Type Safety - Comprehensive DTOs with strict typing and validation
  • โšก HTTP Client Abstraction - Robust error handling, rate limiting, retry logic
  • ๐Ÿงช Fully Tested - Comprehensive test suite with Pest PHP
  • ๐Ÿ“š Rich Documentation - Detailed examples and API reference
  • ๐Ÿ” Developer Friendly - Intuitive API design with IDE autocompletion

๐Ÿ“‹ Requirements

  • PHP 8.4 or higher
  • Composer
  • Instagram Business or Creator Account
  • Facebook App with Instagram API access

๐Ÿ“ฆ Installation

Install via Composer:

composer require mkhab7/php-instagram-graph

โš™๏ธ Configuration

1. Create Facebook App

  1. Go to Facebook Developers
  2. Create a new app with Business type
  3. Add Instagram API product
  4. Configure OAuth redirect URIs

2. Environment Setup

Create a .env file or set environment variables:

INSTAGRAM_APP_ID=your_app_id
INSTAGRAM_APP_SECRET=your_app_secret
INSTAGRAM_REDIRECT_URI=https://yourapp.com/callback

๐Ÿš€ Quick Start

Authentication Flow

<?php

use Mkhab7\InstagramGraph\InstagramGraph;
use Mkhab7\InstagramGraph\Auth\AccessToken;

// Initialize client for authentication
$instagram = InstagramGraph::forAuthentication(
    appId: $_ENV['INSTAGRAM_APP_ID'],
    appSecret: $_ENV['INSTAGRAM_APP_SECRET'],
    redirectUri: $_ENV['INSTAGRAM_REDIRECT_URI']
);

// Step 1: Generate authorization URL
$authUrl = $instagram->auth()->getAuthorizationUrl(
    scopes: ['instagram_business_basic', 'instagram_business_manage_messages'],
    state: 'random_state_string',
    forceReauth: true
);

// Redirect user to $authUrl

// Step 2: Handle callback and exchange code for token
$code = $_GET['code']; // From callback
$accessToken = $instagram->auth()->completeOAuthFlow($code);

// Step 3: Use authenticated client
$authenticatedInstagram = InstagramGraph::withAccessToken(
    appId: $_ENV['INSTAGRAM_APP_ID'],
    appSecret: $_ENV['INSTAGRAM_APP_SECRET'],
    redirectUri: $_ENV['INSTAGRAM_REDIRECT_URI'],
    accessToken: $accessToken
);

Basic Usage

// Get current user information
$user = $authenticatedInstagram->users()->me();

echo "Welcome {$user->getDisplayName()}!\n";
echo "Account Type: {$user->accountType->getLabel()}\n";
echo "Followers: {$user->followersCount}\n";
echo "Media Count: {$user->mediaCount}\n";

// Get user's media
$mediaResponse = $authenticatedInstagram->users()->getUserMedia(limit: 10);

foreach ($mediaResponse['data'] as $mediaData) {
    $media = \Mkhab7\InstagramGraph\Data\Media::fromArray($mediaData);
    
    echo "Media: {$media->id}\n";
    echo "Type: {$media->mediaType->getLabel()}\n";
    echo "Likes: {$media->likesCount}\n";
    echo "Comments: {$media->commentsCount}\n";
    echo "---\n";
}

๐Ÿ“– Comprehensive Usage Guide

๐Ÿ‘ค User Management

$userService = $instagram->users();

// Get current user with custom fields
$user = $userService->me([
    'id', 'username', 'account_type', 'name', 'biography',
    'website', 'followers_count', 'media_count'
]);

// Get another user by ID
$otherUser = $userService->getUser('1234567890');

// Business discovery (public account data)
$publicData = $userService->getBusinessDiscovery('username');

// Check if user exists
if ($userService->userExists('1234567890')) {
    echo "User exists!\n";
}

// Get user insights (business accounts only)
$insights = $userService->getAccountInsights(
    metrics: ['impressions', 'reach', 'profile_views'],
    period: 'day',
    since: new DateTime('-30 days'),
    until: new DateTime('now')
);

๐Ÿ“ธ Media Operations

$mediaService = $instagram->media();

// Get media by ID
$media = $mediaService->getMedia('media_id_here');

echo "Caption: {$media->caption}\n";
echo "Type: {$media->mediaType->getLabel()}\n";
echo "Posted: {$media->timestamp->format('Y-m-d H:i:s')}\n";

// Get media insights
$insights = $mediaService->getMediaInsights(
    mediaId: 'media_id_here',
    metrics: ['impressions', 'reach', 'engagement', 'saves']
);

// Create media container for publishing
$container = $mediaService->createMediaContainer(
    imageUrl: 'https://example.com/image.jpg',
    caption: 'Check out this amazing photo! #photography #art',
    userTags: [
        ['user_id' => '1234567890', 'x' => 0.5, 'y' => 0.3]
    ]
);

// Publish the media
$published = $mediaService->publishMedia($container['id']);

// Create carousel post
$childContainers = [
    $mediaService->createMediaContainer(
        imageUrl: 'https://example.com/image1.jpg',
        isCarouselItem: true
    )['id'],
    $mediaService->createMediaContainer(
        imageUrl: 'https://example.com/image2.jpg',
        isCarouselItem: true
    )['id']
];

$carouselContainer = $mediaService->createCarouselContainer(
    children: $childContainers,
    caption: 'Swipe to see more! ๐Ÿ‘‰'
);

$publishedCarousel = $mediaService->publishMedia($carouselContainer['id']);

// Search hashtags
$hashtags = $mediaService->searchHashtags('travel', limit: 10);

// Get hashtag top media
$topMedia = $mediaService->getHashtagTopMedia('hashtag_id_here');

๐Ÿ’ฌ Comment Management

$commentService = $instagram->comments();

// Get media comments
$comments = $commentService->getMediaComments(
    mediaId: 'media_id_here',
    fields: ['id', 'text', 'timestamp', 'username', 'like_count', 'replies'],
    limit: 50
);

// Create a comment
$newComment = $commentService->createComment(
    mediaId: 'media_id_here',
    message: 'Great post! ๐Ÿ‘'
);

// Reply to a comment
$reply = $commentService->replyToComment(
    commentId: 'comment_id_here',
    message: 'Thanks for the feedback!'
);

// Moderate comments
$moderated = $commentService->moderateComments(
    commentIds: ['comment1', 'comment2', 'comment3'],
    action: 'hide'
);

// Get trending comments (most liked)
$trending = $commentService->getTrendingComments(
    mediaId: 'media_id_here',
    minLikes: 5
);

// Filter comments by keyword
$filtered = $commentService->filterCommentsByKeyword(
    mediaId: 'media_id_here',
    keyword: 'awesome'
);

// Get comment engagement stats
$stats = $commentService->getCommentEngagementStats('media_id_here');
echo "Total Comments: {$stats['total_comments']}\n";
echo "Total Likes: {$stats['total_likes']}\n";
echo "Average Likes per Comment: {$stats['average_likes_per_comment']}\n";

๐Ÿ’ฌ Direct Messaging

$messagingService = $instagram->messaging();

// Send text message
$message = $messagingService->sendTextMessage(
    recipientId: 'user_id_here',
    text: 'Hello! Thanks for reaching out.'
);

// Send image message
$imageMessage = $messagingService->sendImageMessage(
    recipientId: 'user_id_here',
    imageUrl: 'https://example.com/image.jpg'
);

// Send quick reply message
$quickReply = $messagingService->sendQuickReplyMessage(
    recipientId: 'user_id_here',
    text: 'How can we help you today?',
    quickReplies: [
        [
            'content_type' => 'text',
            'title' => 'Support',
            'payload' => 'support'
        ],
        [
            'content_type' => 'text',
            'title' => 'Sales',
            'payload' => 'sales'
        ]
    ]
);

// Send typing indicator
$messagingService->sendTypingIndicator('user_id_here', 'typing_on');

// Get conversations
$conversations = $messagingService->getConversations(limit: 20);

// Get conversation messages
$messages = $messagingService->getConversationMessages(
    conversationId: 'conversation_id_here',
    limit: 50
);

// Mark message as seen
$messagingService->markMessageSeen('user_id_here');

๐Ÿ“Š Analytics & Insights

$insightsService = $instagram->insights();

// Get comprehensive engagement summary
$summary = $insightsService->getEngagementSummary(
    since: new DateTime('-30 days'),
    until: new DateTime('now')
);

echo "Total Impressions: {$summary['total_impressions']}\n";
echo "Total Reach: {$summary['total_reach']}\n";
echo "Engagement Rate: {$summary['engagement_rate']}%\n";

// Get user insights with multiple metrics
$userInsights = $insightsService->getUserInsights(
    metrics: ['impressions', 'reach', 'profile_views', 'website_clicks'],
    period: 'day',
    since: new DateTime('-7 days')
);

// Get audience insights
$audience = $insightsService->getAudienceInsights(
    metrics: ['audience_gender_age', 'audience_locale', 'audience_country']
);

// Get media insights
$mediaInsights = $insightsService->getMediaInsights(
    mediaId: 'media_id_here',
    metrics: ['impressions', 'reach', 'engagement', 'saves', 'video_views']
);

// Get story insights
$storyInsights = $insightsService->getStoryInsights(
    storyId: 'story_id_here',
    metrics: ['impressions', 'reach', 'replies', 'taps_forward', 'exits']
);

// Compare content performance
$comparison = $insightsService->getContentPerformanceComparison(
    mediaIds: ['media1', 'media2', 'media3'],
    metrics: ['impressions', 'engagement']
);

// Get follower growth
$growth = $insightsService->getFollowerGrowthInsights(
    since: new DateTime('-30 days')
);

๐Ÿ”” Webhook Management

$webhookService = $instagram->webhooks();

// Subscribe to webhooks
$subscription = $webhookService->subscribeWebhook(
    object: 'instagram',
    fields: ['messages', 'messaging_postbacks', 'messaging_optins'],
    callbackUrl: 'https://yourapp.com/webhook',
    verifyToken: 'your_verify_token'
);

// Process incoming webhook
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_HUB_SIGNATURE_256'] ?? '';

// Verify signature
if ($webhookService->verifySignature($payload, $signature, $appSecret)) {
    $webhookData = $webhookService->processWebhookPayload($payload);
    
    match ($webhookData['event_type']) {
        'message' => $webhookService->handleMessageWebhook($webhookData),
        'postback' => $webhookService->handlePostbackWebhook($webhookData),
        'delivery' => $webhookService->handleDeliveryWebhook($webhookData),
        default => error_log('Unknown webhook event')
    };
}

// Webhook verification (for initial setup)
$mode = $_GET['hub_mode'] ?? '';
$challenge = $_GET['hub_challenge'] ?? '';
$verifyToken = $_GET['hub_verify_token'] ?? '';

if ($challenge = $webhookService->validateWebhookChallenge(
    $mode, $challenge, $verifyToken, 'your_verify_token'
)) {
    echo $challenge;
}

๐ŸŽฏ Advanced Features

Batch Operations

// Batch get multiple media
$mediaIds = ['media1', 'media2', 'media3'];
$batchResult = $mediaService->batchGetMedia($mediaIds);

foreach ($batchResult as $mediaId => $result) {
    if (isset($result['error'])) {
        echo "Error for {$mediaId}: {$result['error']}\n";
    } else {
        echo "Media {$mediaId} loaded successfully\n";
    }
}

Custom HTTP Options

$instagram = InstagramGraph::withAccessToken(
    appId: $appId,
    appSecret: $appSecret,
    redirectUri: $redirectUri,
    accessToken: $accessToken,
    options: [
        'timeout' => 60,
        'connect_timeout' => 10,
        'headers' => [
            'Custom-Header' => 'value'
        ]
    ]
);

Error Handling

use Mkhab7\InstagramGraph\Exceptions\{
    InstagramGraphException,
    AuthenticationException,
    RateLimitException,
    ValidationException
};

try {
    $user = $instagram->users()->me();
} catch (AuthenticationException $e) {
    if ($e->isExpiredToken()) {
        // Refresh token logic
        $newToken = $instagram->auth()->refreshToken($accessToken);
    }
} catch (RateLimitException $e) {
    $waitTime = $e->getSuggestedWaitTime();
    echo "Rate limited. Wait {$waitTime} seconds.\n";
} catch (ValidationException $e) {
    echo "Validation error: {$e->getMessage()}\n";
    print_r($e->getValidationErrors());
} catch (InstagramGraphException $e) {
    echo "API error: {$e->getMessage()}\n";
    echo "Error type: {$e->getErrorType()}\n";
    echo "Facebook trace ID: {$e->getFacebookTraceId()}\n";
}

๐Ÿงช Testing

Run the test suite:

# Run all tests
composer test

# Run tests with coverage
composer test-coverage

# Run static analysis
composer analyse

# Format code
composer format

Writing Tests

use function Pest\Laravel\{get, post};

it('can get user information', function () {
    $httpClient = mockHttpClient();
    $userService = new UserService($httpClient);
    
    $httpClient
        ->shouldReceive('get')
        ->once()
        ->with('me', ['fields' => 'id,username'])
        ->andReturn(['id' => '123', 'username' => 'test']);
    
    $user = $userService->me(['id', 'username']);
    
    expect($user->id)->toBe('123')
        ->and($user->username)->toBe('test');
});

๐Ÿ”ง Configuration Options

Access Token Management

use Mkhab7\InstagramGraph\Auth\AccessToken;

// Create long-lived token
$longToken = AccessToken::longLived(
    token: 'long_lived_token_string',
    userId: 'user_id',
    scopes: ['instagram_business_basic']
);

// Check token expiration
if ($accessToken->isExpired()) {
    $refreshed = $instagram->auth()->refreshToken($accessToken);
}

// Check token scopes
if ($accessToken->hasScope('instagram_business_manage_messages')) {
    // Can send messages
}

// Token persistence
$tokenData = $accessToken->toJson();
// Store $tokenData in database

// Restore token
$restoredToken = AccessToken::fromJson($tokenData);

Logger Integration

use Monolog\Logger;
use Monolog\Handler\StreamHandler;

$logger = new Logger('instagram');
$logger->pushHandler(new StreamHandler('php://stdout', Logger::DEBUG));

$instagram = InstagramGraph::withAccessToken(
    appId: $appId,
    appSecret: $appSecret,
    redirectUri: $redirectUri,
    accessToken: $accessToken,
    logger: $logger
);

๐Ÿ“š API Reference

Available Scopes

Scope Description
instagram_business_basic Basic access to Instagram business accounts
instagram_business_manage_messages Manage Instagram direct messages
instagram_business_manage_comments Manage comments on Instagram media
instagram_business_content_publish Publish content to Instagram
pages_show_list Access to Facebook pages list
pages_read_engagement Read page engagement data

Rate Limits

Instagram API has the following rate limits:

  • User Access Token: 200 calls per hour per user
  • App Access Token: 200 calls per hour per app
  • Business Discovery: 5 calls per hour per app

The SDK automatically handles rate limit errors and provides retry suggestions.

Media Types

  • IMAGE - Photo posts
  • VIDEO - Video posts (including Reels)
  • CAROUSEL_ALBUM - Multiple photos/videos in one post

๐Ÿค Contributing

We welcome contributions! Please see CONTRIBUTING.md for details.

Development Setup

# Clone repository
git clone https://github.com/mkhab7/php-instagram-graph.git
cd php-instagram-graph

# Install dependencies
composer install

# Run tests
composer test

# Check code style
composer format

# Run static analysis
composer analyse

Code Style

This project follows PSR-12 coding standards and uses PHP-CS-Fixer for formatting.

๐Ÿ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

๐Ÿ™ Acknowledgments

  • Instagram Graph API Documentation
  • PHP-FIG for PSR standards
  • Pest PHP for testing framework
  • All contributors and users

๐Ÿ“ž Support

Made with โค๏ธ by mkhab7