rlnks/sdk
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.
rlnks/sdk 适用场景与选型建议
rlnks/sdk 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 7 次下载、GitHub Stars 达 1, 最近一次更新时间为 2025 年 12 月 04 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「routing」 「image」 「api」 「redirect」 「sdk」 「a-b-testing」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 rlnks/sdk 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 rlnks/sdk 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 rlnks/sdk 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
Yii2 LightBox image galary widget uses Lightbox v2.10.0 by Lokesh Dhakar
The Yii2 extension uses jQuery jquery.carousel-1.1.min.js and makes image carousel from php array of structure defined.
Write down your routing mapping at one place
A PSR-7 compatible library for making CRUD API endpoints
Flight routing is a simple, fast PHP router that is easy to get integrated with other routers.
The Yii2 extension uses jQuery PrettyPhoto and OwlCarousel js and makes image galary from php array of structure defined.
统计信息
- 总下载量: 7
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 1
- 点击次数: 12
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2025-12-04