dg/twitter-php
dg/twitter-php is a lightweight PHP library for the Twitter API, providing simple OAuth authentication and helpers for sending requests, posting tweets, and fetching timelines, user data, and more. Easy to integrate in Laravel or any PHP app.
Installation
composer require dg/x
Requires PHP 8.2+ and Guzzle HTTP client (installed automatically).
Authentication
Register a Twitter Developer account, create a project, and generate Bearer Token (API v2 requires OAuth 2.0 for most endpoints).
Store credentials in .env:
TWITTER_BEARER_TOKEN=your_bearer_token
TWITTER_ACCESS_TOKEN=your_oauth2_token # For write operations
TWITTER_ACCESS_TOKEN_SECRET=your_oauth2_token_secret
First Use Case: Fetching a User’s Tweets (v2)
use DG\X\Client;
$twitter = new Client([
'bearerToken' => env('TWITTER_BEARER_TOKEN'),
'accessToken' => env('TWITTER_ACCESS_TOKEN'),
'accessTokenSecret' => env('TWITTER_ACCESS_TOKEN_SECRET')
]);
$tweets = $twitter->getMyTweets(); // Fetches authenticated user's tweets
dd($tweets);
First Use Case: Posting a Tweet (v2)
$twitter->sendTweet('Hello, Twitter! #Laravel');
Fetching Data (v2 Endpoints)
$twitter->getMyTweets() (authenticated user)
$twitter->getUserTweets($username) (public user)$twitter->search($query, ['max_results' => 10])$twitter->getUser($username)
$twitter->getUserById($userId)$twitter->getMentions()$twitter->getTimeline($username)Posting Content
$twitter->sendTweet($text, ['reply' => ['in_reply_to_tweet_id' => 123]])$twitter->retweet($tweetId) (Note: v2 requires likeTweet for retweets; see Gotchas)$twitter->likeTweet($tweetId)$twitter->sendDirectMessage($targetUserId, $text)Media Handling Upload media via separate endpoint (v2 requires pre-upload):
$media = $twitter->uploadMedia('path/to/image.jpg');
$twitter->sendTweet('Check this out!', ['media' => ['media_ids' => [$media->media_id]]]);
Rate Limiting Check remaining requests (v2 uses 429 responses):
try {
$twitter->getMyTweets();
} catch (\DG\X\Exception\RateLimitExceeded $e) {
$retryAfter = $e->getRetryAfter();
sleep($retryAfter);
}
Laravel Service Provider
Bind the Twitter client in AppServiceProvider:
public function register()
{
$this->app->singleton(Client::class, function ($app) {
return new Client([
'bearerToken' => env('TWITTER_BEARER_TOKEN'),
'accessToken' => env('TWITTER_ACCESS_TOKEN'),
'accessTokenSecret' => env('TWITTER_ACCESS_TOKEN_SECRET')
]);
});
}
Jobs for Async Operations Use Laravel Queues for write operations (e.g., tweets, DMs):
class SendTweetJob implements ShouldQueue
{
public function handle(Client $twitter)
{
$twitter->sendTweet('Scheduled tweet!');
}
}
Caching Responses Cache frequent queries (e.g., user tweets) with Laravel Cache:
$tweets = Cache::remember("twitter_tweets_{$username}", now()->addMinutes(5), function () use ($twitter, $username) {
return $twitter->getUserTweets($username);
});
Pagination
Use ?pagination_token for v2 endpoints (handled internally):
$tweets = $twitter->getMyTweets(['pagination_token' => $nextToken]);
API v2 Breaking Changes
likeTweet() + getTweet() to simulate retweets.
$twitter->likeTweet($tweetId); // "Retweets" via likes in v2
getUserTimeline() with getUserTweets() or getTimeline().Rate Limits (v2)
RateLimitExceeded exceptions.
try {
$twitter->search('laravel');
} catch (\DG\X\Exception\RateLimitExceeded $e) {
sleep($e->getRetryAfter());
}
Media Uploads
media_id in tweets.
$media = $twitter->uploadMedia('image.jpg');
$twitter->sendTweet('Image tweet!', ['media' => ['media_ids' => [$media->media_id]]]);
Character Limits
if (mb_strlen($text, 'UTF-8') > 280) {
throw new \InvalidArgumentException('Tweet exceeds 280 characters.');
}
User IDs vs. Usernames
getUserById() for deterministic lookups.
$user = $twitter->getUserById(12345); // Reliable
$user = $twitter->getUser('twitterdev'); // May resolve to ID
Enable Debugging
Pass debug: true to log raw responses:
$twitter = new Client([...], ['debug' => true]);
Common Errors
| Error | Cause | Solution |
|---|---|---|
401 Unauthorized |
Invalid Bearer/OAuth token | Regenerate tokens in Twitter Dev Portal |
403 Forbidden |
Scope missing (e.g., tweet.read) |
Add required scopes to OAuth app |
404 Not Found |
Invalid user/tweet ID | Validate inputs |
429 Too Many Requests |
Rate limit exceeded | Implement retries with Retry-After |
400 Bad Request |
Malformed media/tweet payload | Validate payload structure |
Custom Endpoints (v2) Use the underlying Guzzle client for unsupported endpoints:
$response = $twitter->getClient()->get('https://api.twitter.com/2/users/by/username/twitterdev');
Middleware Attach Guzzle middleware for logging/auth:
$twitter->getClient()->getEmitter()->attach(
\DG\X\Middleware\LogMiddleware::class
);
Testing
Use pest or phpunit with HTTP mocking:
use DG\X\Tests\TestCase;
public function test_send_tweet()
{
$twitter = new Client([...]);
$response = $twitter->sendTweet('Test');
$this->assertEquals(201, $response->getStatusCode());
}
Webhooks (v2) For real-time updates, use Twitter’s Rules API or Filters API (requires separate setup).
Laravel HTTP Client Proxy requests via Laravel’s HTTP client for consistency:
$twitter = new Client([...]);
$response = Http::withOptions(['debug' => true])
->macro('twitter', fn ($method, $url, $data = []) => $twitter->{$method}($url, $data))
->twitter('get', '/2/tweets/search', ['
How can I help you explore Laravel packages today?