tourze / tus-upload-server-bundle
TUS (Tus Resumable Upload) 文件上传服务端实现包
Installs: 0
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/tourze/tus-upload-server-bundle
Requires
- ext-hash: *
- doctrine/dbal: ^4.0
- doctrine/doctrine-bundle: ^2.13
- doctrine/doctrine-fixtures-bundle: ^4.0
- doctrine/orm: ^3.0
- doctrine/persistence: ^4.1
- easycorp/easyadmin-bundle: ^4
- knplabs/knp-menu: ^3.7
- league/flysystem: ^3.10
- ramsey/uuid: ^4.7
- symfony/config: ^7.3
- symfony/console: ^7.3
- symfony/dependency-injection: ^7.3
- symfony/doctrine-bridge: ^7.3
- symfony/framework-bundle: ^7.3
- symfony/http-foundation: ^7.3
- symfony/http-kernel: ^7.3
- symfony/property-access: ^7.3
- symfony/routing: ^7.3
- symfony/yaml: ^7.3
- tourze/bundle-dependency: 1.*
- tourze/doctrine-indexed-bundle: 1.0.*
- tourze/doctrine-timestamp-bundle: 1.0.*
- tourze/easy-admin-menu-bundle: 1.0.*
- tourze/file-storage-bundle: 1.0.*
- tourze/symfony-dependency-service-loader: 1.0.*
- tourze/symfony-routing-auto-loader-bundle: 1.0.*
Requires (Dev)
This package is auto-updated.
Last update: 2025-11-03 06:25:25 UTC
README
A Symfony bundle implementing the TUS resumable upload protocol version 1.0.0.
Table of Contents
- Features
- Installation
- Configuration
- Dependencies
- Usage
- Advanced Usage
- Commands
- Services
- Events
- Testing
- Security Considerations
- License
Features
- Complete TUS 1.0.0 protocol implementation
- File storage using Flysystem (defaults to local filesystem)
- Database storage for upload metadata
- Support for upload expiration and cleanup
- Checksum validation (MD5, SHA1, SHA256)
- CORS support for browser uploads
- Configurable upload size limits
Installation
composer require tourze/tus-upload-server-bundle
Configuration
Add the bundle to your config/bundles.php:
return [ // ... Tourze\TusUploadServerBundle\TusUploadServerBundle::class => ['all' => true], ];
Configure the bundle using environment variables in your .env file:
# Storage path for uploaded files (defaults to /tmp/tus-uploads) TUS_UPLOAD_STORAGE_PATH=/var/tus-uploads # Upload path for service (defaults to /tmp/tus-uploads) TUS_UPLOAD_PATH=/var/tus-uploads
Configure routing manually or use the controller service directly. The bundle provides a TusUploadController that can be accessed at your desired paths through your application's routing configuration.
Dependencies
This bundle requires the following dependencies:
Core Dependencies
- PHP 8.1+ - Required for modern PHP features and type declarations
- Symfony 6.4+ - Framework foundation
- Doctrine ORM 3.0+ - For database entity management
- League Flysystem 3.10+ - File storage abstraction layer
Symfony Components
symfony/config- Configuration systemsymfony/console- Command line interfacesymfony/dependency-injection- Service containersymfony/framework-bundle- Core framework bundlesymfony/http-foundation- HTTP abstractionssymfony/routing- URL routing systemsymfony/validator- Data validation
Optional Dependencies
- Redis/Memcached - For distributed locking (recommended for production)
- AWS S3/Google Cloud - For cloud file storage
- Database - MySQL, PostgreSQL, or SQLite for metadata storage
Database Setup
Create and run the migration for the Upload entity:
php bin/console doctrine:migrations:diff php bin/console doctrine:migrations:migrate
Usage
Endpoints
The bundle provides the following endpoints:
OPTIONS /tus/files- Get server capabilitiesPOST /tus/files- Create a new uploadHEAD /tus/files/{uploadId}- Get upload infoPATCH /tus/files/{uploadId}- Upload file chunkDELETE /tus/files/{uploadId}- Delete upload
JavaScript Client Example
// Create upload const response = await fetch('/tus/files', { method: 'POST', headers: { 'Tus-Resumable': '1.0.0', 'Upload-Length': file.size, 'Upload-Metadata': `filename ${btoa(file.name)},filetype ${btoa(file.type)}` } }); const uploadUrl = response.headers.get('Location'); // Upload file in chunks const chunkSize = 1024 * 1024; // 1MB chunks let offset = 0; while (offset < file.size) { const chunk = file.slice(offset, offset + chunkSize); await fetch(uploadUrl, { method: 'PATCH', headers: { 'Tus-Resumable': '1.0.0', 'Upload-Offset': offset, 'Content-Type': 'application/offset+octet-stream' }, body: chunk }); offset += chunk.size; }
TUS.js Integration
This bundle is compatible with the tus-js-client:
import * as tus from 'tus-js-client'; const upload = new tus.Upload(file, { endpoint: '/tus/files', retryDelays: [0, 3000, 5000, 10000, 20000], metadata: { filename: file.name, filetype: file.type }, onError: function(error) { console.log('Failed because: ' + error); }, onProgress: function(bytesUploaded, bytesTotal) { const percentage = (bytesUploaded / bytesTotal * 100).toFixed(2); console.log(bytesUploaded, bytesTotal, percentage + '%'); }, onSuccess: function() { console.log('Download %s from %s', upload.file.name, upload.url); } }); upload.start();
Advanced Usage
Custom Storage Configuration
You can configure different storage backends by implementing a custom filesystem factory:
<?php namespace App\Service; use League\Flysystem\Filesystem; use League\Flysystem\AwsS3V3\AwsS3V3Adapter; use Aws\S3\S3Client; class CustomFilesystemFactory { public function createS3Filesystem(): Filesystem { $client = new S3Client([ 'credentials' => [ 'key' => $_ENV['AWS_ACCESS_KEY_ID'], 'secret' => $_ENV['AWS_SECRET_ACCESS_KEY'], ], 'region' => $_ENV['AWS_DEFAULT_REGION'], 'version' => 'latest', ]); $adapter = new AwsS3V3Adapter($client, $_ENV['AWS_BUCKET']); return new Filesystem($adapter); } }
Custom Upload Path Strategy
Implement a custom upload path strategy:
<?php namespace App\Service; use Tourze\TusUploadServerBundle\Entity\Upload; class DateBasedUploadPathStrategy { public function generatePath(Upload $upload): string { $date = $upload->getCreateTime()->format('Y/m/d'); $hash = substr(md5($upload->getUploadId()), 0, 8); return sprintf('uploads/%s/%s/%s', $date, $hash, $upload->getFilename()); } }
Event-Driven Processing
Handle upload events for custom processing:
<?php namespace App\EventSubscriber; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Tourze\TusUploadServerBundle\Event\UploadCompletedEvent; use Tourze\TusUploadServerBundle\Event\UploadCreatedEvent; class UploadProcessingSubscriber implements EventSubscriberInterface { public static function getSubscribedEvents(): array { return [ UploadCreatedEvent::class => 'onUploadCreated', UploadCompletedEvent::class => 'onUploadCompleted', ]; } public function onUploadCreated(UploadCreatedEvent $event): void { $upload = $event->getUpload(); // Log upload creation, check quotas, etc. } public function onUploadCompleted(UploadCompletedEvent $event): void { $upload = $event->getUpload(); // Process completed file, generate thumbnails, scan for viruses, etc. // Example: Move file to final destination $finalPath = sprintf('processed/%s', $upload->getFilename()); // ... move file logic } }
Performance Optimization
For high-traffic scenarios, consider these optimizations:
1. Database Indexing
-- Add indexes for frequent queries CREATE INDEX idx_tus_uploads_created_expired ON tus_uploads(created_at, expired_time); CREATE INDEX idx_tus_uploads_upload_id ON tus_uploads(upload_id);
2. Caching Upload Metadata
<?php use Symfony\Contracts\Cache\CacheInterface; class CachedUploadService { public function __construct( private readonly TusUploadService $tusUploadService, private readonly CacheInterface $cache ) {} public function getUpload(string $uploadId): ?Upload { return $this->cache->get( "upload.{$uploadId}", fn() => $this->tusUploadService->getUpload($uploadId) ); } }
3. Chunked Upload Optimization
# config/packages/tus_upload.yaml tus_upload: chunk_size: 1048576 # 1MB chunks max_file_size: 1073741824 # 1GB max file size cleanup_interval: 3600 # Cleanup every hour
Commands
Cleanup Expired Uploads
php bin/console tus:cleanup
This command removes expired uploads from both the database and filesystem.
Services
TusUploadService
The main service for handling uploads:
use Tourze\TusUploadServerBundle\Service\TusUploadService; class YourService { public function __construct( private TusUploadService $tusUploadService ) {} public function processCompletedUpload(string $uploadId): void { $upload = $this->tusUploadService->getUpload($uploadId); if ($upload->isCompleted()) { $content = $this->tusUploadService->getFileContent($upload); // Process the file content... } } }
Events
You can listen to upload events by creating event subscribers:
use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Tourze\TusUploadServerBundle\Event\UploadCompletedEvent; class UploadEventSubscriber implements EventSubscriberInterface { public static function getSubscribedEvents(): array { return [ UploadCompletedEvent::class => 'onUploadCompleted', ]; } public function onUploadCompleted(UploadCompletedEvent $event): void { $upload = $event->getUpload(); // Handle completed upload... } }
Testing
Run the test suite:
vendor/bin/phpunit
Security Considerations
- Configure appropriate upload size limits
- Implement authentication/authorization as needed
- Consider virus scanning for uploaded files
- Set up proper file cleanup policies
- Monitor disk usage for uploaded files
License
This bundle is released under the MIT License.