snowsoft/cdn-laravel-adapter
Composer 安装命令:
composer require snowsoft/cdn-laravel-adapter
包简介
Laravel Storage adapter for CDN Services Node.js backend
README 文档
README
Laravel Storage adapter for CDN Services Node.js backend. Use CDN Services as a Laravel filesystem disk (Laravel 9, 10, 11, 12). Domain Driven Design (DDD) uyumlu yapı: Domain (value objects, port interfaces), Application (use case services), Infrastructure (HTTP gateway).
- Packagist: packagist.org/packages/snowsoft/cdn-laravel-adapter
- Source: github.com/snowsoft/cdn-laravel-adapter
Özellikler
| Özellik | Açıklama |
|---|---|
| Storage disk | Storage::disk('cdn-services') ile put/get/delete/url, caption, tags, folder, visibility |
| CdnServicesAuth | Kayıt (registration token), giriş, tokenForUser ile JWT |
| Depolama kotası | QuotaExceededException, getQuotaRemaining(), usage() ile quotaBytes/quotaMB |
| CdnServicesPdf | PDF yükleme, HTML'den PDF oluşturma (generateFromHtml), session ile süreli erişim, DDD (PdfDocument, PdfSession) |
| CdnServicesApi | Meta, list, usage, import, placeholder, signed URL, processedUrl, Cloudflare cloudflareProcessedUrl |
| CdnApi / CdnBulk | Toplu işlem: CdnApi::upload, importBatch, bulkDelete; CdnBulk::uploadMany; Artisan: cdn:bulk-upload, cdn:import-urls, cdn:bulk-delete |
| CdnMinify | JS/CSS sıkıştırma (minify), publish (ledger + kalıcı asset), ledger doğrulama; DDD (MinifyPublishResult, LedgerVerification). |
DDD yapısı
| Katman | Açıklama |
|---|---|
| Domain | Domain\Pdf\PdfDocument, PdfSession (value objects); PdfStorageGatewayInterface (port). Minify: Domain\Minify\MinifyPublishResult, LedgerVerification; MinifyGatewayInterface (port). |
| Application | Application\Pdf\PdfStorageService – PDF use case'leri. Minify: Application\Minify\MinifyService – minifyJs, minifyCss, publishJs, publishCss, assetUrl, verifyLedger. |
| Infrastructure | Infrastructure\Http\PdfStorageGateway – backend /api/pdf/*. Minify: Infrastructure\Http\MinifyGateway – backend /api/minify/*. |
| Bulk (Contracts/Services) | Contracts\CdnApiClientInterface, CdnBulkUploadServiceInterface; Services\CdnApiClient, CdnBulkUploadService; DTOs: BulkUploadResult, BatchImportResult, BulkDeleteResult. |
Bağımlılık Domain → Application → Infrastructure yönünde; uygulama PdfStorageGatewayInterface / MinifyGatewayInterface ile tip bağımlılığı kurar, implementasyon ServiceProvider'da bağlanır.
Minify (DDD)
Backend’de Minify servisi açıksa (MINIFY_SERVICE_URL), CdnMinify facade ile JS/CSS sıkıştırma, yayınlama (ledger + asset) ve ledger doğrulama kullanılır:
use CdnServices\Facades\CdnMinify; use CdnServices\Domain\Minify\MinifyPublishResult; // Sadece sıkıştır (kaydetmez) $minifiedJs = CdnMinify::minifyJs($rawJs); $minifiedCss = CdnMinify::minifyCss($rawCss); // Yayınla: sıkıştır + ledger'a yaz + kalıcı asset URL $result = CdnMinify::publishJs($rawJs); // MinifyPublishResult: assetId, url, kind, size $result = CdnMinify::publishCss($rawCss); // Asset erişim URL'i (script/link ile kullanılır) $url = CdnMinify::assetUrl($result->assetId); // Ledger zincir doğrulama $verification = CdnMinify::verifyLedger(); // LedgerVerification: valid, message, entries if (CdnMinify::isAvailable()) { // Minify servisi kullanılabilir }
Toplu işlem (DDD: CdnApi, CdnBulk, Artisan)
Servisler: CdnApiClientInterface (upload, importBatch, bulkDelete), CdnBulkUploadServiceInterface (uploadMany). Facades: CdnApi, CdnBulk (alias'ları eklemek için config/app.php veya composer extra.laravel.aliases içine CdnApi → CdnServices\Facades\CdnApi, CdnBulk → CdnServices\Facades\CdnBulk ekleyin).
Artisan komutları:
# Toplu dosya yükleme (dizin veya tek dosya) php artisan cdn:bulk-upload /path/to/products --bucket=local --folder=ürünler --tags=ürün,yeni # URL listesinden import (--file= veya argüman) php artisan cdn:import-urls --file=urls.txt --bucket=local # Toplu silme php artisan cdn:bulk-delete --file=ids.txt
Kod örneği:
use CdnServices\Contracts\CdnBulkUploadServiceInterface; use CdnServices\Facades\CdnApi; use CdnServices\DTOs\BatchImportResult; use CdnServices\DTOs\BulkDeleteResult; // Toplu yükleme (controller'da inject) $result = app(CdnBulkUploadServiceInterface::class)->uploadMany( ['/path/to/1.jpg', '/path/to/2.png'], ['bucket' => 'local', 'folder' => 'ürünler'] ); $result->uploadedIds(); // URL import $res = CdnApi::importBatch(['https://example.com/1.jpg'], ['bucket' => 'local']); $result = BatchImportResult::fromApiResponse($res); // Toplu silme $res = CdnApi::bulkDelete(['id1', 'id2']); $result = BulkDeleteResult::fromApiResponse($res);
Requirements
- PHP 8.0+
- Laravel 9.x, 10.x, 11.x or 12.x
- CDN Services Node.js backend
Installation
Install via Composer (Packagist):
composer require snowsoft/cdn-laravel-adapter
Service provider and aliases are auto-discovered. Publish config:
php artisan vendor:publish --tag=cdn-services-config
Install from GitHub (development)
Add the VCS repository to composer.json, then require the package:
{
"repositories": [
{
"type": "vcs",
"url": "https://github.com/snowsoft/cdn-laravel-adapter"
}
]
}
composer require snowsoft/cdn-laravel-adapter
Manual install
- Clone the repo into your project (e.g.
packages/cdn-laravel-adapter). - Add PSR-4 autoload:
"CdnServices\\": "packages/cdn-laravel-adapter/src/". - Register
CdnServices\CdnServicesServiceProviderinconfig/app.phporbootstrap/providers.php. - Run
php artisan vendor:publish --tag=cdn-services-config.
Configuration
Environment (.env)
CDN_SERVICES_BASE_URL=http://localhost:3012 CDN_SERVICES_TOKEN=your-jwt-token-here # Backend'de REGISTRATION_TOKEN zorunluysa; kayıt için (CdnServicesAuth::register) CDN_SERVICES_REGISTRATION_TOKEN= CDN_SERVICES_DISK=local CDN_SERVICES_DEFAULT_DISK=local CDN_SERVICES_TIMEOUT=30
Filesystem (config/filesystems.php)
'disks' => [ // ... 'cdn-services' => [ 'driver' => 'cdn-services', 'base_url' => env('CDN_SERVICES_BASE_URL', 'http://localhost:3012'), 'token' => env('CDN_SERVICES_TOKEN'), 'disk' => env('CDN_SERVICES_DISK', 'local'), ], ],
Usage
Storage facade
use Illuminate\Support\Facades\Storage; // Upload (optional: caption, tags, folder, visibility) Storage::disk('cdn-services')->put('images/photo.jpg', $fileContents, [ 'caption' => 'Açıklama', 'tags' => ['ürün', 'kampanya'], 'folder' => 'galeri', 'visibility' => 'public', // public|private|unlisted ]); // Read, exists, delete, url, copy, move $contents = Storage::disk('cdn-services')->get('images/photo.jpg'); $exists = Storage::disk('cdn-services')->exists('images/photo.jpg'); Storage::disk('cdn-services')->delete('images/photo.jpg'); $url = Storage::disk('cdn-services')->url('images/photo.jpg'); Storage::disk('cdn-services')->copy('images/photo.jpg', 'images/photo-copy.jpg'); Storage::disk('cdn-services')->move('images/photo.jpg', 'images/new-photo.jpg');
CdnServicesAuth – kayıt, giriş, token
Backend'de kullanıcı kaydı (registration token zorunlu olabilir), giriş ve CDN işlemleri için JWT almak:
use CdnServices\Facades\CdnServicesAuth; // Kayıt (registration token config'ten veya 2. parametre ile) $result = CdnServicesAuth::register([ 'email' => 'user@example.com', 'password' => 'secret123', 'name' => 'Ad Soyad', ]); // $result['token'] → JWT (CDN_SERVICES_TOKEN olarak kullanılabilir) // $result['user'] → id, email, name, role, createdAt // Giriş $result = CdnServicesAuth::login('user@example.com', 'secret123'); if ($result) { $jwt = $result['token']; } // Sunucu tarafında bir kullanıcı için JWT üret (CDN işlemleri için) $tokenPayload = CdnServicesAuth::tokenForUser($userId, 'user@example.com', 'user'); $jwt = $tokenPayload['token'] ?? null; // Kayıt için token zorunlu mu? if (CdnServicesAuth::requiresRegistrationToken()) { // Config'te CDN_SERVICES_REGISTRATION_TOKEN tanımlı }
CdnServices facade
use CdnServices\Facades\CdnServices; CdnServices::put('images/photo.jpg', $fileContents); $contents = CdnServices::get('images/photo.jpg'); $url = CdnServices::url('images/photo.jpg');
Upload with UploadedFile
use Illuminate\Http\Request; use Illuminate\Support\Facades\Storage; public function upload(Request $request) { $request->validate(['image' => 'required|image|max:51200']); // 50MB $path = Storage::disk('cdn-services')->put('images', $request->file('image')); return response()->json([ 'success' => true, 'path' => $path, 'url' => Storage::disk('cdn-services')->url($path), ]); }
CdnServicesApi – meta, list, usage (kota), import, placeholder, signed URL, processed URL
use CdnServices\Facades\CdnServicesApi; $info = CdnServicesApi::getInfo($imageId); $images = CdnServicesApi::listImages(['tag' => 'ürün', 'favorite' => true]); CdnServicesApi::updateMeta($imageId, ['caption' => 'Yeni başlık', 'visibility' => 'private']); CdnServicesApi::replace($imageId, $request->file('image')); $usage = CdnServicesApi::usage(); // fileCount, totalSize, totalSizeMB, viewCountTotal, quotaBytes?, quotaMB? $quotaRemaining = CdnServicesApi::getQuotaRemaining(); // null if no quota $file = CdnServicesApi::importFromUrl('https://example.com/photo.jpg'); $file = CdnServicesApi::createPlaceholder(['width' => 800, 'height' => 600, 'text' => 'Placeholder']); $result = CdnServicesApi::bulkDelete(['id1', 'id2']); $signed = CdnServicesApi::getSignedUrl($imageId, 3600); $url = CdnServicesApi::processedUrl($imageId, '800x600', 'webp', [ 'quality' => 80, 'fit' => 'cover', 'filter' => 'sepia', 'crop' => 'smart', 'watermark' => true, ]);
Different backend disks (S3, Azure, etc.)
Storage::disk('cdn-services')->put('images/photo.jpg', $fileContents, ['disk' => 's3']); Storage::disk('cdn-services')->put('images/photo.jpg', $fileContents, ['disk' => 'azure']);
Processed image URLs
$originalUrl = Storage::disk('cdn-services')->url($imageId); $thumb = CdnServicesApi::processedUrl($imageId, 'thumbnail', 'jpeg'); $custom = CdnServicesApi::processedUrl($imageId, '800x600', 'webp', ['quality' => 75, 'watermark' => true]);
Cloudflare Image Resizing
Backend’de Cloudflare Image Resizing açıksa, edge’de resize/format/quality için URL alınır:
$url = CdnServicesApi::cloudflareProcessedUrl($imageId, '800x600', 'webp', [ 'quality' => 80, 'fit' => 'cover', 'crop' => 'smart', ]); // Backend GET /api/image/{id}/cloudflare-url ile aynı parametreler
Detay: CDN Services docs/CLOUDFLARE_IMAGE_RESIZING.md.
CdnServicesPdf – PDF depolama (blockchain, süreli session)
Backend'de PDF_STORAGE_ENABLED=true ise kullanılır; resim alanından bağımsızdır.
use CdnServices\Facades\CdnServicesPdf; use CdnServices\Domain\Pdf\PdfDocument; use CdnServices\Domain\Pdf\PdfSession; if (!CdnServicesPdf::isEnabled()) { return; // PDF storage kapalı } // Yükle (value object döner) // Yükleme veya HTML'den oluşturma (backend'de PDF_GENERATE_SERVICE_URL gerekir) $doc = CdnServicesPdf::upload($request->file('pdf')); // veya: $doc = CdnServicesPdf::generateFromHtml('<html><body><h1>Rapor</h1></body></html>', 'rapor.pdf'); if ($doc instanceof PdfDocument) { $id = $doc->id; } // Listele $documents = CdnServicesPdf::list(); // list<PdfDocument> // Süreli erişim session'ı al $session = CdnServicesPdf::createSession($doc->id); if ($session instanceof PdfSession) { $url = CdnServicesPdf::sessionUrl($session); // GET ile PDF açılır // veya: $session->url(config('cdn-services.base_url')); } // Sil CdnServicesPdf::delete($doc->id);
Constructor injection (DDD): Uygulama sınıflarında port kullanmak için:
use CdnServices\Domain\Pdf\PdfStorageGatewayInterface; class MyController extends Controller { public function __construct( private PdfStorageGatewayInterface $pdfStorage ) {} }
Customization
Custom base URL: set base_url in config/filesystems.php for the cdn-services disk.
Dynamic token: in your service provider, when extending the disk, get config and call $adapter->setToken(auth()->user()->cdn_token) (or your logic) before returning the adapter.
Storage quota and exceptions
When the backend has USER_STORAGE_QUOTA_BYTES set, uploads (Storage put, API replace, importFromUrl, createPlaceholder) may return 413. The adapter throws CdnServices\Exceptions\QuotaExceededException so you can catch and show a friendly message:
use CdnServices\Exceptions\QuotaExceededException; try { Storage::disk('cdn-services')->put('images/photo.jpg', $contents); } catch (QuotaExceededException $e) { return back()->with('error', 'Depolama limitiniz doldu.'); }
CdnServicesApi::usage() includes quotaBytes and quotaMB when a quota is set; use getQuotaRemaining() to show remaining space.
Troubleshooting
| Problem | Check |
|---|---|
| Connection refused | Backend running: curl http://localhost:3012/health |
| Unauthorized | Valid JWT in CDN_SERVICES_TOKEN; create token via backend /api/auth/token |
| File not found | Use image ID (not path) when calling URL/meta APIs |
| QuotaExceededException | Backend USER_STORAGE_QUOTA_BYTES limit reached; free space or increase quota |
API quick reference
Storage put() options: disk, caption, tags, folder, visibility
CdnServicesAuth: register, login, tokenForUser, getRegistrationToken, requiresRegistrationToken
CdnServicesPdf (DDD): upload(UploadedFile), generateFromHtml(html, filename), list(), createSession(documentId), sessionUrl(PdfSession), delete(documentId), isEnabled()
CdnServicesApi: getInfo, listImages, updateMeta, replace, usage, getQuotaBytes, getQuotaRemaining, importFromUrl, createPlaceholder, bulkDelete, getSignedUrl, processedUrl, cloudflareProcessedUrl
Disk methods: exists, get, put, delete, copy, move, size, lastModified, mimeType, url, temporaryUrl, readStream, writeStream, files
License
MIT
snowsoft/cdn-laravel-adapter 适用场景与选型建议
snowsoft/cdn-laravel-adapter 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 157 次下载、GitHub Stars 达 0, 最近一次更新时间为 2026 年 02 月 12 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「image」 「filesystem」 「storage」 「cdn」 「laravel」 「cdn-services」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 snowsoft/cdn-laravel-adapter 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 snowsoft/cdn-laravel-adapter 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 snowsoft/cdn-laravel-adapter 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
A SDK for working with B2 cloud storage.
A PHP class providing static methods for reading, writing, copying, moving, and deleting files and directories, MIME type detection, image size detection, and file permission management
Small library to access Microsoft Windows Azure Blob Storage with a Service or a StreamWrapper.
Yii2 LightBox image galary widget uses Lightbox v2.10.0 by Lokesh Dhakar
The flysystem adapter for yandex disk rest api.
The Yii2 extension uses jQuery jquery.carousel-1.1.min.js and makes image carousel from php array of structure defined.
统计信息
- 总下载量: 157
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 16
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2026-02-12