rlnks/sdk
最新稳定版本:v1.0.4
Composer 安装命令:
composer require rlnks/sdk
包简介
Official PHP SDK for the RLNKS API - Smart redirect and image routing
README 文档
README
Official PHP SDK for the RLNKS API - Smart redirect and image routing.
Requirements
- PHP 8.1 or higher
- Guzzle HTTP client
Installation
Install via Composer:
composer require rlnks/sdk
Quick Start
<?php require_once 'vendor/autoload.php'; use Rlnks\Client; // Initialize the client with your API key $client = new Client('rlnks_your_api_key'); // List your decision trees $trees = $client->trees->list(); foreach ($trees as $tree) { echo $tree->name . ' - ' . $tree->getImageUrl() . "\n"; }
Authentication
The SDK supports API key authentication. Your API key can be found in your RLNKS dashboard.
// API keys start with 'rlnks_' $client = new Client('rlnks_your_api_key'); // You can also specify custom options $client = new Client('rlnks_your_api_key', [ 'base_url' => 'https://app.rlnks.com/api/v1', // Custom base URL 'timeout' => 30, // Request timeout in seconds 'connect_timeout' => 10, // Connection timeout ]);
Decision Trees
Decision trees are the core of RLNKS. They define conditional logic for serving different images or redirecting to different URLs.
List Trees
// List all trees $trees = $client->trees->list(); // Filter by type $imageTrees = $client->trees->list(['type' => 'image']); $redirectTrees = $client->trees->list(['type' => 'redirect']); // Filter by status $activeTrees = $client->trees->list(['status' => 'active']); // Search and pagination $trees = $client->trees->list([ 'search' => 'campaign', 'sort_by' => 'name', 'sort_dir' => 'asc', 'per_page' => 50, 'page' => 1, ]); // Iterate through results foreach ($trees as $tree) { echo "{$tree->name}: {$tree->total_requests} requests\n"; } // Check pagination if ($trees->hasNextPage()) { echo "More trees available...\n"; }
Create a Tree
$tree = $client->trees->create([ 'name' => 'Holiday Campaign', 'type' => 'image', 'description' => 'Banner images for holiday season', 'tree_data' => [ 'root' => [ 'id' => 'node_1', 'type' => 'condition', 'criteria' => [ 'field' => 'device.type', 'operator' => 'equals', 'value' => 'mobile', ], 'true_branch' => ['type' => 'output', 'id' => 'mobile_banner'], 'false_branch' => ['type' => 'output', 'id' => 'desktop_banner'], ], ], 'default_output' => [ 'type' => 'image', 'image_id' => 'your-image-uuid', ], ]); // Get the generated URLs echo "Image URL: " . $tree->getImageUrl() . "\n"; echo "Short URL: " . $tree->getShortUrl() . "\n";
Update a Tree
$tree = $client->trees->update($treeId, [ 'name' => 'Updated Campaign Name', 'is_active' => true, ]);
Activate/Deactivate a Tree
// Activate $client->trees->activate($treeId); // Deactivate $client->trees->deactivate($treeId); // Archive $client->trees->archive($treeId);
Clone a Tree
$clonedTree = $client->trees->clone($treeId, [ 'name' => 'Copy of Holiday Campaign', ]);
Test a Tree
// Test with simulated context $result = $client->trees->test($treeId, [ 'device' => [ 'type' => 'mobile', 'brand' => 'Apple', 'model' => 'iPhone 15', ], 'location' => [ 'country' => 'CA', ], ]); echo "Matched node: " . $result['node_id'] . "\n"; echo "Output: " . json_encode($result['output']) . "\n";
Delete a Tree
$client->trees->delete($treeId);
Images
Upload and manage images that can be used in image-type decision trees.
List Images
// List all images $images = $client->images->list(); // Filter by folder $holidayImages = $client->images->list(['folder' => 'holiday2024']); // Search $images = $client->images->list(['search' => 'banner']); foreach ($images as $image) { echo "{$image->filename} ({$image->dimensions}) - {$image->human_size}\n"; }
Upload an Image
// Upload from file path $image = $client->images->upload('/path/to/banner.jpg', [ 'name' => 'Holiday Banner Mobile', 'folder' => 'holiday2024', ]); echo "Uploaded: " . $image->url . "\n"; echo "Thumbnail: " . $image->thumbnail_url . "\n"; // Upload from string content $imageContent = file_get_contents('https://example.com/image.jpg'); $image = $client->images->uploadFromString($imageContent, 'downloaded.jpg', [ 'folder' => 'external', ]);
Get Folders
$folders = $client->images->getFolders(); // ['holiday2024', 'banners', 'products']
Update Image
// Rename $image = $client->images->rename($imageId, 'New Name'); // Move to folder $image = $client->images->moveToFolder($imageId, 'new-folder');
Delete an Image
$client->images->delete($imageId);
Analytics
Access performance analytics for your decision trees.
Get Tree Analytics
// Get last 7 days (default) $analytics = $client->analytics->getTreeAnalytics($treeId); // Specific periods $analytics = $client->analytics->getToday($treeId); $analytics = $client->analytics->getLast7Days($treeId); $analytics = $client->analytics->getLast30Days($treeId); // Custom date range $analytics = $client->analytics->getDateRange($treeId, '2024-01-01', '2024-01-31'); // Access the data echo "Total views: " . $analytics['summary']['total_views'] . "\n"; echo "Click rate: " . $analytics['summary']['click_rate'] . "%\n"; // Timeline data foreach ($analytics['timeline'] as $day) { echo "{$day['date']}: {$day['views']} views, {$day['clicks']} clicks\n"; } // Device distribution foreach ($analytics['devices'] as $device => $count) { echo "{$device}: {$count}\n"; }
Get Breakdown by Dimension
// Device breakdown $breakdown = $client->analytics->getDeviceBreakdown($treeId); // Browser breakdown $breakdown = $client->analytics->getBrowserBreakdown($treeId); // Country breakdown $breakdown = $client->analytics->getCountryBreakdown($treeId); // Output node breakdown (A/B test results) $breakdown = $client->analytics->getOutputBreakdown($treeId); // Custom dimension $breakdown = $client->analytics->getBreakdown($treeId, 'os', [ 'period' => '30d', ]);
Webhooks
Set up webhooks to receive real-time notifications about events in your account.
List Webhooks
$webhooks = $client->webhooks->list(); foreach ($webhooks as $webhook) { echo "{$webhook->name}: {$webhook->getSuccessRate()}% success rate\n"; }
Create a Webhook
$webhook = $client->webhooks->create([ 'name' => 'My Integration', 'url' => 'https://example.com/webhook', 'events' => [ 'tree.created', 'tree.updated', 'usage.limit_warning', ], 'headers' => [ 'X-Custom-Header' => 'value', ], 'timeout_seconds' => 30, 'retry_count' => 3, ]); // Save the secret for signature verification $secret = $webhook->secret;
Update a Webhook
// Enable/disable $client->webhooks->enable($webhookId); $client->webhooks->disable($webhookId); // Add events $client->webhooks->addEvents($webhookId, ['tree.deleted']); // Remove events $client->webhooks->removeEvents($webhookId, ['tree.updated']);
Test a Webhook
$result = $client->webhooks->test($webhookId); echo "Test delivery status: " . $result['status'] . "\n";
Get Deliveries
$deliveries = $client->webhooks->getDeliveries($webhookId); foreach ($deliveries['data'] as $delivery) { echo "{$delivery['event']} - {$delivery['status_code']} - {$delivery['created_at']}\n"; }
Regenerate Secret
$result = $client->webhooks->regenerateSecret($webhookId); $newSecret = $result['secret'];
Handling Webhooks
When receiving webhooks, always verify the signature before processing:
<?php use Rlnks\Webhook\SignatureVerifier; use Rlnks\Webhook\WebhookEvent; $verifier = new SignatureVerifier('your_webhook_secret'); // Get the raw payload and headers $payload = file_get_contents('php://input'); $signature = $_SERVER['HTTP_X_RLNKS_SIGNATURE'] ?? ''; $timestamp = $_SERVER['HTTP_X_RLNKS_TIMESTAMP'] ?? ''; try { // Verify and parse the webhook $data = $verifier->verifyAndParse($payload, $signature, $timestamp); // Create an event object for easier handling $event = WebhookEvent::fromPayload($data); // Handle different event types switch ($event->getEventType()) { case WebhookEvent::TREE_CREATED: echo "Tree created: " . $event->getTreeName(); break; case WebhookEvent::TREE_UPDATED: echo "Tree updated: " . $event->getTreeId(); break; case WebhookEvent::USAGE_LIMIT_WARNING: echo "Usage warning! Current: " . $event->get('current_usage'); break; case WebhookEvent::USAGE_LIMIT_REACHED: echo "Usage limit reached!"; break; } // Check event categories if ($event->isTreeEvent()) { // Handle all tree events } if ($event->isUsageEvent()) { // Handle usage alerts } http_response_code(200); } catch (\Rlnks\Exceptions\RlnksException $e) { // Invalid signature or payload http_response_code(401); echo "Webhook verification failed: " . $e->getMessage(); }
Custom Domains
Serve your links from your own domain for white-label solutions and brand consistency.
List Domains
$domains = $client->customDomains->list(); foreach ($domains as $domain) { echo "{$domain->domain}: {$domain->getStatusDescription()}\n"; } // Get only active domains $activeDomains = $client->customDomains->getActive(); // Get pending domains (awaiting verification or SSL) $pendingDomains = $client->customDomains->getPending();
Add a Domain
// Add a new custom domain $domain = $client->customDomains->create('links.example.com'); // Get DNS setup instructions $instructions = $client->customDomains->getDnsInstructions($domain->id); echo "CNAME Target: " . $instructions['cname_target'] . "\n"; echo "TXT Record Name: " . $instructions['txt_record_name'] . "\n"; echo "TXT Record Value: " . $instructions['txt_record_value'] . "\n"; // Or create with instructions in one call $result = $client->customDomains->createWithInstructions('links.example.com'); $domain = $result['domain']; $instructions = $result['dns'];
Verify and Activate
// After configuring DNS records, verify the domain $domain = $client->customDomains->verify($domainId); // Check status if ($domain->isActive()) { echo "Domain is active and ready to use!\n"; } elseif ($domain->isPendingSsl()) { echo "SSL certificate is being provisioned...\n"; } elseif ($domain->hasSslError()) { // Retry SSL provisioning $domain = $client->customDomains->retrySsl($domainId); }
Set Default Domain
// Set as default for all trees $client->customDomains->setDefault($domainId); // Remove from defaults $client->customDomains->unsetDefault($domainId); // Get current default $default = $client->customDomains->getDefault();
Check Availability
if ($client->customDomains->checkAvailability('links.example.com')) { echo "Domain is available!\n"; }
Delete a Domain
$client->customDomains->delete($domainId);
Ephemeral Links (Test Links)
Create temporary links for testing decision trees without affecting production statistics.
Create Test Links
// Create a test link for an image tree $link = $client->ephemeralLinks->create($treeId, [ 'type' => 'image', 'expires_in_minutes' => 15, // 5-60 minutes 'max_uses' => 10, // Optional: limit uses ]); echo "Test URL: " . $link->getUrl() . "\n"; echo "Expires: " . $link->getRemainingTime() . "\n"; // Convenience methods $imageLink = $client->ephemeralLinks->createImageLink($treeId, 30); // 30 minutes $redirectLink = $client->ephemeralLinks->createRedirectLink($treeId); // Quick URL generation $url = $client->ephemeralLinks->createAndGetUrl($treeId, 'image', 15);
Test with Variable Slugs
Variable slugs allow testing different condition paths with a single tree.
$link = $client->ephemeralLinks->createImageLink($treeId); // Test different conditions using the slug echo $link->getUrlWithSlug('logo'); // /test/i/{uuid}/logo echo $link->getUrlWithSlug('banner'); // /test/i/{uuid}/banner echo $link->getUrlWithSlug('header'); // /test/i/{uuid}/header // The slug is available in tree conditions as 'slug' field: // - slug equals "logo" -> Show logo image // - slug equals "banner" -> Show banner image
List and Manage Links
// List active links for a tree $links = $client->ephemeralLinks->list($treeId); // Include expired links $allLinks = $client->ephemeralLinks->list($treeId, ['include_expired' => true]); // Get only valid (non-expired) links $validLinks = $client->ephemeralLinks->getValid($treeId); // Get a specific link $link = $client->ephemeralLinks->get($linkUuid); // Delete a link $client->ephemeralLinks->delete($linkUuid); // Clean up expired links $deletedCount = $client->ephemeralLinks->deleteExpired($treeId); echo "Deleted {$deletedCount} expired links\n";
Link Properties
$link = $client->ephemeralLinks->get($linkUuid); // Check status $link->isValid(); // Still usable? $link->isExpired(); // Time expired? $link->hasUseLimit(); // Has max uses? // Usage info $link->use_count; // Current uses $link->getRemainingUses(); // Uses left (null if unlimited) $link->getRemainingTime(); // "5 minutes from now" // Type $link->isImageLink(); // true/false $link->isRedirectLink(); // true/false
Variable Slugs in Tree Conditions
Variable slugs enable condition-based routing with a single URL. This allows one tree to handle multiple use cases (e.g., different banners for different contexts).
URL Format
/i/{tree_uuid}/{optional-slug}/{variable-slug}
/r/{tree_uuid}/{optional-slug}/{variable-slug}
Examples:
/i/abc123/campaign/logo- variable slug is "logo"/i/abc123/campaign/banner- variable slug is "banner"/r/xyz789/email/cta1- variable slug is "cta1"
Using in Tree Conditions
When building a tree, use the slug field in conditions:
$tree = $client->trees->create([ 'name' => 'Multi-Banner Campaign', 'type' => 'image', 'tree_data' => [ 'root' => [ 'id' => 'node_1', 'type' => 'condition', 'criteria' => [ 'field' => 'slug', // Use the variable slug 'operator' => 'equals', 'value' => 'logo', ], 'true_branch' => [ 'type' => 'output', 'id' => 'logo_output', 'image_id' => 'logo-image-uuid', ], 'false_branch' => [ 'id' => 'node_2', 'type' => 'condition', 'criteria' => [ 'field' => 'slug', 'operator' => 'equals', 'value' => 'banner', ], 'true_branch' => [ 'type' => 'output', 'id' => 'banner_output', 'image_id' => 'banner-image-uuid', ], 'false_branch' => [ 'type' => 'output', 'id' => 'default_output', 'image_id' => 'default-image-uuid', ], ], ], ], ]); // Use the same tree for different images $logoUrl = $tree->getImageUrl() . '/campaign/logo'; $bannerUrl = $tree->getImageUrl() . '/campaign/banner';
Testing Variable Slugs
// Test tree with different slugs $result = $client->trees->test($treeId, [ 'slug' => 'logo', ]); echo "Logo output: " . $result['output']['image_id'] . "\n"; $result = $client->trees->test($treeId, [ 'slug' => 'banner', ]); echo "Banner output: " . $result['output']['image_id'] . "\n"; // Or use ephemeral links for browser testing $link = $client->ephemeralLinks->createImageLink($treeId); echo "Test logo: " . $link->getUrlWithSlug('logo') . "\n"; echo "Test banner: " . $link->getUrlWithSlug('banner') . "\n";
Account
Manage your account settings and monitor usage.
Get Account Info
$account = $client->account->get(); echo "Name: " . $account['name'] . "\n"; echo "Plan: " . $account['plan']['name'] . "\n"; echo "Email: " . $account['email'] . "\n";
Get Usage
$usage = $client->account->getUsage(); echo "Requests this month: " . $usage['current_month']['requests'] . "\n"; echo "Limit: " . $usage['current_month']['limit'] . "\n"; echo "Remaining: " . $usage['current_month']['remaining'] . "\n"; // Convenience methods echo "Usage: " . $client->account->getUsagePercentage() . "%\n"; echo "Remaining: " . $client->account->getRemainingRequests() . "\n"; if ($client->account->isOverLimit()) { echo "Warning: Over usage limit!\n"; }
Get Plan Limits
Get a comprehensive summary of all plan limits and current usage:
$limits = $client->account->getLimits(); // Plan info echo "Plan: " . $limits['plan']['name'] . "\n"; // Request limits (monthly) echo "Requests: " . $limits['requests']['used'] . "/" . $limits['requests']['limit'] . "\n"; echo "Remaining: " . $limits['requests']['remaining'] . "\n"; echo "Period: " . $limits['requests']['period'] . "\n"; // Trees limits echo "Trees: " . $limits['trees']['used'] . "/" . $limits['trees']['limit'] . "\n"; if ($limits['trees']['unlimited']) { echo "Trees: Unlimited\n"; } // Images limits echo "Images: " . $limits['images']['used'] . "/" . $limits['images']['limit'] . "\n"; // Storage info echo "Storage used: " . $limits['storage']['used_human'] . "\n"; echo "Max file size: " . $limits['storage']['max_file_size_mb'] . " MB\n"; // Convenience methods $client->account->getRemainingTrees(); // int or null if unlimited $client->account->getRemainingImages(); // int or null if unlimited $client->account->getStorageUsed(); // bytes $client->account->getStorageUsedHuman(); // "45.2 MB" $client->account->hasReachedTreesLimit(); // bool $client->account->hasReachedImagesLimit(); // bool // Check before creating resources if ($client->account->hasReachedTreesLimit()) { echo "Cannot create more trees - limit reached!\n"; }
Update Account
$client->account->update([ 'name' => 'John Doe', 'company' => 'Acme Inc', 'timezone' => 'America/Toronto', 'locale' => 'en', ]);
Error Handling
The SDK throws specific exceptions for different error types:
use Rlnks\Exceptions\AuthenticationException; use Rlnks\Exceptions\AuthorizationException; use Rlnks\Exceptions\NotFoundException; use Rlnks\Exceptions\ValidationException; use Rlnks\Exceptions\RateLimitException; use Rlnks\Exceptions\RlnksException; try { $tree = $client->trees->get('invalid-id'); } catch (AuthenticationException $e) { // Invalid API key echo "Authentication failed: " . $e->getMessage(); } catch (AuthorizationException $e) { // Insufficient permissions echo "Access denied: " . $e->getMessage(); echo "Error code: " . $e->getErrorCode(); } catch (NotFoundException $e) { // Resource not found echo "Not found: " . $e->getMessage(); } catch (ValidationException $e) { // Validation errors echo "Validation failed: " . $e->getMessage(); // Get field-level errors foreach ($e->getValidationErrors() as $field => $errors) { echo "{$field}: " . implode(', ', $errors) . "\n"; } // Check specific field if ($e->hasFieldError('name')) { echo "Name error: " . $e->getFieldErrors('name')[0]; } } catch (RateLimitException $e) { // Rate limited echo "Rate limited. Retry after: " . $e->getRetryAfter() . " seconds\n"; echo "Limit: " . $e->getLimit() . "\n"; echo "Remaining: " . $e->getRemaining() . "\n"; } catch (RlnksException $e) { // Other API errors echo "Error: " . $e->getMessage(); echo "Code: " . $e->getErrorCode(); }
Rate Limiting
The SDK automatically extracts rate limit information from responses:
// Make any API call $trees = $client->trees->list(); // Check rate limit status $rateLimit = $client->getRateLimitInfo(); echo "Limit: " . $rateLimit['limit'] . "\n"; echo "Remaining: " . $rateLimit['remaining'] . "\n"; echo "Reset at: " . date('Y-m-d H:i:s', $rateLimit['reset']) . "\n";
Pagination
Paginated responses provide convenient methods for iteration:
$trees = $client->trees->list(['per_page' => 20]); // Basic info echo "Page " . $trees->getCurrentPage() . " of " . $trees->getTotalPages() . "\n"; echo "Showing " . $trees->count() . " of " . $trees->getTotalCount() . " total\n"; // Navigation if ($trees->hasNextPage()) { $nextPage = $client->trees->list([ 'per_page' => 20, 'page' => $trees->getCurrentPage() + 1, ]); } // Iterate foreach ($trees as $tree) { echo $tree->name . "\n"; } // Get first/last $firstTree = $trees->first(); $lastTree = $trees->last(); // Check if empty if ($trees->isEmpty()) { echo "No trees found.\n"; }
Models
Response data is returned as model objects with helpful methods:
Tree Model
$tree = $client->trees->get($treeId); // Properties echo $tree->id; echo $tree->name; echo $tree->type; // 'image' or 'redirect' echo $tree->short_code; echo $tree->is_active; echo $tree->total_requests; // Methods echo $tree->getImageUrl(); // https://app.rlnks.com/i/{uuid} echo $tree->getRedirectUrl(); // https://app.rlnks.com/r/{uuid} echo $tree->getShortUrl(); // https://app.rlnks.com/go/{code} $tree->isImageTree(); // true/false $tree->isRedirectTree(); // true/false $tree->getCreatedAt(); // DateTimeImmutable $tree->getLastRequestAt(); // DateTimeImmutable or null
Image Model
$image = $client->images->get($imageId); echo $image->url; echo $image->thumbnail_url; echo $image->filename; echo $image->dimensions; // '1200x600' echo $image->human_size; // '44.26 KB' $image->getWidth(); // 1200 $image->getHeight(); // 600 $image->getSize(); // bytes $image->isJpeg(); $image->isPng(); $image->isWebp(); $image->inFolder('holiday2024');
Testing
The SDK includes helpers for testing your integration:
use Rlnks\Webhook\SignatureVerifier; // Create test signatures $verifier = new SignatureVerifier('test_secret'); $payload = json_encode(['event' => 'tree.created', 'data' => []]); $signed = $verifier->sign($payload); // Use in tests $signature = $signed['signature']; $timestamp = $signed['timestamp'];
License
MIT License. See LICENSE file for details.
统计信息
- 总下载量: 7
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 1
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2025-12-04