PHP code example of owlstack / owlstack-core

1. Go to this page and download the library: Download owlstack/owlstack-core library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

owlstack / owlstack-core example snippets


use Owlstack\Core\Content\Post;
use Owlstack\Core\Content\Media;
use Owlstack\Core\Content\MediaCollection;
use Owlstack\Core\Config\PlatformCredentials;
use Owlstack\Core\Http\HttpClient;
use Owlstack\Core\Platforms\PlatformRegistry;
use Owlstack\Core\Platforms\Telegram\TelegramPlatform;
use Owlstack\Core\Platforms\Telegram\TelegramFormatter;
use Owlstack\Core\Publishing\Publisher;

// 1. Configure credentials
$credentials = new PlatformCredentials('telegram', [
    'api_token' => 'your-bot-token',
    'channel_username' => '@your-channel',
]);

// 2. Create platform
$httpClient  = new HttpClient();
$formatter   = new TelegramFormatter();
$platform    = new TelegramPlatform($credentials, $httpClient, $formatter);

// 3. Register & publish
$registry = new PlatformRegistry();
$registry->register($platform);

$publisher = new Publisher($registry);
$post = new Post(
    title: 'Hello World',
    body: 'My first post via Owlstack!',
    url: 'https://example.com/hello-world',
    tags: ['opensource', 'php'],
);

$result = $publisher->publish($post, 'telegram');

if ($result->success) {
    echo "Published! ID: {$result->externalId}";
    echo "URL: {$result->externalUrl}";
} else {
    echo "Failed: {$result->error}";
}

use Owlstack\Core\Content\Post;

$post = new Post(
    title: 'My Article Title',
    body: 'The full article content goes here...',
    url: 'https://example.com/my-article',        // optional
    excerpt: 'A short summary for Twitter',        // optional
    media: $mediaCollection,                       // optional
    tags: ['php', 'social-media', 'automation'],   // optional
    metadata: ['wp_post_id' => 42],                // optional
);

// Helpers
$post->hasMedia();                    // bool
$post->hasUrl();                      // bool
$post->getMeta('wp_post_id');         // 42
$post->getMeta('missing', 'default'); // 'default'

use Owlstack\Core\Content\Media;

$image = new Media(
    path: '/path/to/photo.jpg',
    mimeType: 'image/jpeg',
    altText: 'A sunset over the ocean',
    width: 1920,
    height: 1080,
    fileSize: 245_000,
);

$image->isImage();    // true
$image->isVideo();    // false
$image->isAudio();    // false
$image->isDocument(); // false

use Owlstack\Core\Content\MediaCollection;

$collection = new MediaCollection();
$collection = $collection->add($image1);
$collection = $collection->add($image2);
$collection = $collection->add($video);

$collection->count();    // 3
$collection->first();    // $image1
$collection->images();   // MediaCollection with $image1, $image2
$collection->videos();   // MediaCollection with $video
$collection->isEmpty();  // false
$collection->all();      // Media[]

// Iterable
foreach ($collection as $media) {
    echo $media->path;
}

use Owlstack\Core\Content\CanonicalLink;

$link = new CanonicalLink("\n\nRead more: {url}");
$text = $link->inject($content, 'https://example.com', maxLength: 280);

use Owlstack\Core\Config\PlatformCredentials;

$creds = new PlatformCredentials('twitter', [
    'consumer_key' => '...',
    'consumer_secret' => '...',
    'access_token' => '...',
    'access_token_secret' => '...',
]);

$creds->get('consumer_key');         // value
$creds->has('consumer_key');         // true
$creds->

use Owlstack\Core\Config\OwlstackConfig;

$config = new OwlstackConfig(
    platforms: [
        'telegram' => ['api_token' => '...'],
        'twitter'  => ['consumer_key' => '...', /* ... */],
    ],
    options: [
        'default_hashtag_count' => 5,
    ],
);

$config->hasPlatform('telegram');    // true
$config->credentials('telegram');    // PlatformCredentials
$config->configuredPlatforms();      // ['telegram', 'twitter']
$config->option('default_hashtag_count'); // 5

use Owlstack\Core\Config\ConfigValidator;

$validator = new ConfigValidator();
$missing = $validator->validate($credentials); // ['access_token_secret']

// Or validate all platforms at once (throws on failure)
$validator->validateConfig($config);

use Owlstack\Core\Publishing\Publisher;

$publisher = new Publisher($registry, $eventDispatcher); // dispatcher is optional

$result = $publisher->publish($post, 'telegram', ['chat_id' => '@channel']);

$result->success;       // bool
$result->failed();      // bool (inverse of success)
$result->platformName;  // 'telegram'
$result->externalId;    // '12345' or null
$result->externalUrl;   // 'https://t.me/channel/12345' or null
$result->error;         // 'Rate limit exceeded' or null
$result->timestamp;     // DateTimeImmutable

use Owlstack\Core\Formatting\Contracts\FormatterInterface;

// Every formatter implements:
$formatter->format($post, $options);  // Formatted string
$formatter->platform();               // 'telegram'
$formatter->maxLength();              // 4096

use Owlstack\Core\Formatting\CharacterTruncator;

$truncator = new CharacterTruncator(ellipsis: '…');
$truncator->truncate('Hello World', maxLength: 8); // 'Hello…'

use Owlstack\Core\Formatting\HashtagExtractor;

$extractor = new HashtagExtractor();
$extractor->extract(['PHP', 'social media'], maxCount: 5);
// '#PHP #socialmedia'

use Owlstack\Core\Auth\OAuthHandler;
use Owlstack\Core\Auth\AccessToken;

// Set up handler (provider & store are interface implementations)
$handler = new OAuthHandler($provider, $tokenStore, 'twitter');

// Step 1: Generate authorization URL
$authUrl = $handler->authorize('https://app.com/callback', ['tweet.read', 'tweet.write']);

// Step 2: Handle callback after user authorizes
$token = $handler->handleCallback($code, 'https://app.com/callback', 'user-123');

// Step 3: Get valid token (auto-refreshes if expired)
$token = $handler->getToken('user-123');

$token = new AccessToken(
    token: 'abc123',
    refreshToken: 'refresh_xyz',
    expiresAt: new DateTimeImmutable('+1 hour'),
    scopes: ['tweet.read', 'tweet.write'],
    metadata: ['user_id' => '12345'],
);

$token->isExpired();     // false
$token->isRefreshable(); // true

use Owlstack\Core\Events\Contracts\EventDispatcherInterface;
use Owlstack\Core\Events\PostPublished;
use Owlstack\Core\Events\PostFailed;

class MyDispatcher implements EventDispatcherInterface
{
    public function dispatch(object $event): void
    {
        match (true) {
            $event instanceof PostPublished => $this->onPublished($event),
            $event instanceof PostFailed    => $this->onFailed($event),
        };
    }

    private function onPublished(PostPublished $event): void
    {
        // $event->post — the Post object
        // $event->result — the PublishResult
        logger("Published to {$event->result->platformName}");
    }

    private function onFailed(PostFailed $event): void
    {
        logger("Failed: {$event->result->error}");
    }
}

$publisher = new Publisher($registry, new MyDispatcher());

use Owlstack\Core\Delivery\DeliveryStatus;

$status = DeliveryStatus::Pending;     // 'pending'
$status = DeliveryStatus::Publishing;  // 'publishing'
$status = DeliveryStatus::Published;   // 'published'
$status = DeliveryStatus::Failed;      // 'failed'

use Owlstack\Core\Exceptions\RateLimitException;
use Owlstack\Core\Exceptions\ContentTooLongException;
use Owlstack\Core\Exceptions\MediaValidationException;

try {
    $response = $platform->publish($post);
} catch (RateLimitException $e) {
    $seconds = $e->retryAfterSeconds();
    sleep($seconds ?? 60);
    // retry...
} catch (ContentTooLongException $e) {
    echo "Content is {$e->actualLength} chars, max is {$e->maxLength} for {$e->platformName}";
} catch (MediaValidationException $e) {
    echo "Invalid media: {$e->mimeType} not supported on {$e->platformName}";
}

use Owlstack\Core\Http\HttpClient;

$client = new HttpClient(
    timeout: 30,
    connectTimeout: 10,
    verifySsl: true,
    proxy: [
        'host' => 'proxy.example.com',
        'port' => 8080,
        'type' => CURLPROXY_HTTP,
        'auth' => 'user:pass',
    ],
);

// JSON request
$response = $client->post('https://api.example.com/posts', [
    'headers' => ['Authorization' => 'Bearer token'],
    'json' => ['message' => 'Hello'],
]);

// Multipart file upload
$response = $client->post('https://api.example.com/upload', [
    'multipart' => [
        ['name' => 'file', 'contents' => '/path/to/file.jpg', 'filename' => 'photo.jpg'],
    ],
]);

// $response = ['status' => 200, 'headers' => [...], 'body' => '...']

use Owlstack\Core\Support\Arr;

Arr::get($data, 'user.profile.name', 'Unknown'); // Dot-notation access
Arr::filterEmpty(['a' => 1, 'b' => null, 'c' => '']); // ['a' => 1]
Arr::only($data, ['name', 'email']); // Whitelist keys

use Owlstack\Core\Support\Str;

Str::limit('Hello World', 8, '…'); // 'Hello…'
Str::slug('My Article Title');      // 'my-article-title'
Str::startsWith('Hello', 'He');    // true

use Owlstack\Core\Support\Clock;

Clock::now();        // DateTimeImmutable
Clock::timestamp();  // int

// In tests: freeze time
Clock::freeze(new DateTimeImmutable('2025-01-01 12:00:00'));
Clock::now(); // always 2025-01-01 12:00:00
Clock::unfreeze();

$credentials = new PlatformCredentials('telegram', [
    'api_token' => 'your-bot-token',
    'channel_username' => '@your-channel',
]);

$platform = new TelegramPlatform($credentials, new HttpClient(), new TelegramFormatter());

// Publish with options
$result = $publisher->publish($post, 'telegram', [
    'chat_id' => '@specific-channel',
    'parse_mode' => 'HTML',
    'disable_notification' => true,
    'inline_keyboard' => [
        [['text' => 'Visit Site', 'url' => 'https://example.com']],
    ],
]);

// Extended methods
$platform->sendLocation($chatId, 40.7128, -74.0060);
$platform->sendVenue($chatId, 40.7128, -74.0060, 'NYC Office', '123 Main St');
$platform->sendContact($chatId, '+1234567890', 'John');
$platform->pinMessage($chatId, $messageId);

$credentials = new PlatformCredentials('twitter', [
    'consumer_key' => '...',
    'consumer_secret' => '...',
    'access_token' => '...',
    'access_token_secret' => '...',
]);

$result = $publisher->publish($post, 'twitter', [
    'reply_to' => '1234567890',
    'quote_tweet_id' => '9876543210',
    'poll' => [
        'options' => ['Yes', 'No', 'Maybe'],
        'duration_minutes' => 1440,
    ],
]);

$credentials = new PlatformCredentials('facebook', [
    'app_id' => '...',
    'app_secret' => '...',
    'page_access_token' => '...',
    'page_id' => '...',
]);

$result = $publisher->publish($post, 'facebook', [
    'privacy' => ['value' => 'EVERYONE'],
    'scheduled_publish_time' => time() + 3600,
]);

// Personal profile
$credentials = new PlatformCredentials('linkedin', [
    'access_token' => '...',
    'person_id' => 'abc123',
]);

// Or company page
$credentials = new PlatformCredentials('linkedin', [
    'access_token' => '...',
    'organization_id' => 'org456',
]);

$result = $publisher->publish($post, 'linkedin', [
    'visibility' => 'PUBLIC',
]);

// Bot mode
$credentials = new PlatformCredentials('discord', [
    'bot_token' => '...',
    'channel_id' => '...',
]);

// Or webhook mode
$credentials = new PlatformCredentials('discord', [
    'webhook_url' => 'https://discord.com/api/webhooks/...',
]);

$result = $publisher->publish($post, 'discord', [
    'embed' => true,      // Rich embed with title, description, color
    'color' => 0x5865F2,  // Embed color
    'thread_id' => '...',
    'tts' => false,
]);

$credentials = new PlatformCredentials('instagram', [
    'access_token' => '...',
    'instagram_account_id' => '...',
]);

$result = $publisher->publish($post, 'instagram', [
    'media_type' => 'IMAGE',    // IMAGE, REELS, or STORIES
    'image_url' => 'https://example.com/photo.jpg',
    'location_id' => '...',
    'alt_text' => 'Photo description',
    // Carousel
    'carousel' => [
        ['image_url' => 'https://example.com/1.jpg'],
        ['image_url' => 'https://example.com/2.jpg'],
    ],
]);

$credentials = new PlatformCredentials('pinterest', [
    'access_token' => '...',
    'board_id' => '...',
]);

$result = $publisher->publish($post, 'pinterest', [
    'board_section_id' => '...',
    'image_url' => 'https://example.com/pin.jpg',
    'alt_text' => 'Pin description',
    'dominant_color' => '#FF5733',
]);

$credentials = new PlatformCredentials('reddit', [
    'client_id' => '...',
    'client_secret' => '...',
    'access_token' => '...',
    'username' => 'your_username',
]);

$result = $publisher->publish($post, 'reddit', [
    'subreddit' => 'php',          // 

// Bot token mode
$credentials = new PlatformCredentials('slack', [
    'bot_token' => 'xoxb-...',
    'channel' => '#general',
]);

// Or webhook mode
$credentials = new PlatformCredentials('slack', [
    'webhook_url' => 'https://hooks.slack.com/services/...',
]);

$result = $publisher->publish($post, 'slack', [
    'blocks' => true,          // Use Block Kit layout
    'thread_ts' => '...',      // Reply in thread
    'unfurl_links' => true,
]);

$credentials = new PlatformCredentials('tumblr', [
    'access_token' => '...',
    'blog_identifier' => 'myblog.tumblr.com',
]);

$result = $publisher->publish($post, 'tumblr', [
    'post_type' => 'text',     // text, image, video, link, audio
    'state' => 'published',    // published, draft, queue, private
    'slug' => 'my-post-slug',
]);

$credentials = new PlatformCredentials('whatsapp', [
    'access_token' => '...',
    'phone_number_id' => '...',
]);

$result = $publisher->publish($post, 'whatsapp', [
    'to' => '+1234567890',              // 

$registry = new PlatformRegistry();
$registry->register($telegramPlatform);
$registry->register($twitterPlatform);
$registry->register($discordPlatform);

$publisher = new Publisher($registry);

$post = new Post(
    title: 'New Release: v2.0',
    body: 'We are excited to announce version 2.0 with multi-platform support!',
    url: 'https://example.com/releases/v2',
    tags: ['release', 'opensource'],
);

// Publish to all registered platforms
$results = [];
foreach ($registry->names() as $name) {
    $results[$name] = $publisher->publish($post, $name);
}

// Check results
foreach ($results as $platform => $result) {
    echo $result->success
        ? "✓ {$platform}: {$result->externalUrl}\n"
        : "✗ {$platform}: {$result->error}\n";
}

use Owlstack\Core\Platforms\Contracts\PlatformInterface;
use Owlstack\Core\Platforms\Contracts\PlatformResponseInterface;
use Owlstack\Core\Platforms\PlatformResponse;
use Owlstack\Core\Content\Post;

class MastodonPlatform implements PlatformInterface
{
    public function name(): string
    {
        return 'mastodon';
    }

    public function publish(Post $post, array $options = []): PlatformResponseInterface
    {
        // Your implementation...
        return PlatformResponse::success(
            externalId: '12345',
            externalUrl: 'https://mastodon.social/@user/12345',
            rawResponse: $apiResponse,
        );
    }

    public function delete(string $externalId): bool
    {
        // Your implementation...
        return true;
    }

    public function validateCredentials(): bool
    {
        // Your implementation...
        return true;
    }

    public function constraints(): array
    {
        return [
            'max_text_length' => 500,
            'max_media_count' => 4,
            'supported_media_types' => ['image/jpeg', 'image/png', 'image/gif'],
            'max_media_size' => 10 * 1024 * 1024,
        ];
    }
}

use Owlstack\Core\Formatting\Contracts\FormatterInterface;
use Owlstack\Core\Content\Post;

class MastodonFormatter implements FormatterInterface
{
    public function format(Post $post, array $options = []): string
    {
        // Build formatted content for Mastodon...
        return $formatted;
    }

    public function platform(): string
    {
        return 'mastodon';
    }

    public function maxLength(): int
    {
        return 500;
    }
}

use Owlstack\Core\Auth\Contracts\TokenStoreInterface;
use Owlstack\Core\Auth\AccessToken;

class DatabaseTokenStore implements TokenStoreInterface
{
    public function get(string $platform, string $accountId): ?AccessToken { /* ... */ }
    public function store(string $platform, string $accountId, AccessToken $token): void { /* ... */ }
    public function revoke(string $platform, string $accountId): void { /* ... */ }
    public function has(string $platform, string $accountId): bool { /* ... */ }
}

$client = new HttpClient(
    proxy: [
        'host' => 'proxy.example.com',
        'port' => 8080,
        'type' => CURLPROXY_SOCKS5,
        'auth' => 'username:password',
    ],
);

use Owlstack\Core\Support\Clock;

Clock::freeze(new DateTimeImmutable('2025-06-15 10:00:00'));
// All Clock::now() calls return the frozen time
Clock::unfreeze();