tourze/file-storage-bundle
最新稳定版本:1.1.0
Composer 安装命令:
composer require tourze/file-storage-bundle
包简介
Symfony bundle for file storage management with upload, validation, and cleanup features
README 文档
README
Symfony Bundle for file upload and storage management with Flysystem integration.
Table of Contents
- Features
- Installation
- Configuration
- Database Setup
- Usage
- File Type Management
- Console Commands
- Advanced Storage Configuration
- Entity Structure
- Security
- Dependencies
- Advanced Usage
- Testing
- License
Features
- Flysystem integration for flexible file storage (local, S3, FTP, etc.)
- Separate upload endpoints for anonymous and authenticated users
- Database-driven file type management with configurable permissions
- File metadata storage in database with user tracking
- Automatic file hash calculation (MD5, SHA1)
- File organization by year/month structure
- Soft delete support
- Automatic cleanup of anonymous files
- File statistics
- Duplicate detection by hash
- EasyAdmin integration ready
Installation
composer require tourze/file-storage-bundle
Configuration
Add the bundle to your config/bundles.php:
return [ // ... Tourze\FileStorageBundle\FileStorageBundle::class => ['all' => true], ];
The bundle automatically configures Flysystem with a local adapter. No additional configuration is needed for basic usage.
Database Setup
Run migrations to create the required tables:
bin/console doctrine:migrations:diff bin/console doctrine:migrations:migrate
Load default file types:
bin/console doctrine:fixtures:load --append --group=file-types
Usage
Anonymous Upload
POST /api/files/upload/anonymous Content-Type: multipart/form-data file: <file>
Response:
{
"success": true,
"file": {
"id": 1,
"originalName": "document.pdf",
"fileName": "document-65abc123.pdf",
"mimeType": "application/pdf",
"fileSize": 1048576,
"md5Hash": "098f6bcd4621d373cade4e832627b4f6",
"createdAt": "2024-01-10 10:30:00"
}
}
Note: Anonymous files are automatically deleted after 1 hour.
Member Upload
POST /api/files/upload/member Authorization: Bearer <token> Content-Type: multipart/form-data file: <file>
Response:
{
"success": true,
"file": {
"id": 2,
"originalName": "report.xlsx",
"fileName": "report-65abc456.xlsx",
"mimeType": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"fileSize": 2097152,
"md5Hash": "5d41402abc4b2a76b9719d911017c592",
"createdAt": "2024-01-10 11:00:00",
"userId": 123
}
}
Get Allowed File Types
# For anonymous users GET /api/files/allowed-types/anonymous # For members GET /api/files/allowed-types/member
Response:
{
"allowedTypes": [
{
"name": "JPEG Image",
"mimeType": "image/jpeg",
"extension": "jpg",
"maxSize": 10485760
},
{
"name": "PDF Document",
"mimeType": "application/pdf",
"extension": "pdf",
"maxSize": 20971520
}
]
}
Get File Info
GET /api/files/{id}
File Type Management
File types are stored in the database and can be managed via EasyAdmin or programmatically:
// Create a new file type $fileType = new FileType(); $fileType->setName('PowerPoint Presentation') ->setMimeType('application/vnd.ms-powerpoint') ->setExtension('ppt') ->setMaxSize(30 * 1024 * 1024) // 30MB ->setUploadType('member') // 'anonymous', 'member', or 'both' ->setIsActive(true); $entityManager->persist($fileType); $entityManager->flush();
Console Commands
Clean Anonymous Files
Remove anonymous files older than specified hours:
# Delete anonymous files older than 1 hour (default) bin/console file-storage:clean-anonymous # Delete anonymous files older than 3 hours bin/console file-storage:clean-anonymous --hours=3 # Dry run - show what would be deleted without actually deleting bin/console file-storage:clean-anonymous --dry-run # Verbose output showing file details bin/console file-storage:clean-anonymous --dry-run -v
Delete Files
Delete all files in a specified directory recursively:
# Delete all files in a directory (requires confirmation) bin/console file-storage:delete path/to/directory # Skip confirmation prompt bin/console file-storage:delete path/to/directory --force # Also delete empty directories bin/console file-storage:delete path/to/directory --include-dirs # Dry run - show what would be deleted without actually deleting bin/console file-storage:delete path/to/directory --dry-run # Verbose output showing file details bin/console file-storage:delete path/to/directory --dry-run -v # Combined: delete files and directories with force bin/console file-storage:delete path/to/directory -f -d
Cron Job Example
Add to your crontab to run every hour:
0 * * * * cd /path/to/project && bin/console file-storage:clean-anonymous
File Statistics
Display file storage statistics:
# Show file statistics bin/console file-storage:stats # Output example: # File Storage Statistics # ======================= # Total files: 1,234 # Total size: 5.67 GB # Average file size: 4.71 MB # Anonymous files: 456 # Member files: 778
Advanced Storage Configuration
The bundle uses Flysystem for file storage abstraction. By default, it uses a local filesystem adapter.
Custom Storage Adapter
To use a different storage backend (e.g., AWS S3, FTP, etc.), create your own factory:
// src/Factory/S3FilesystemFactory.php namespace App\Factory; use Aws\S3\S3Client; use League\Flysystem\AwsS3V3\AwsS3V3Adapter; use League\Flysystem\Filesystem; use League\Flysystem\FilesystemOperator; class S3FilesystemFactory { public function __construct( private readonly S3Client $s3Client, private readonly string $bucket, ) { } public function createFilesystem(): FilesystemOperator { $adapter = new AwsS3V3Adapter($this->s3Client, $this->bucket); return new Filesystem($adapter); } }
Entity Structure
File Entity
originalName- Original uploaded filenamefileName- Generated unique filenamefilePath- Relative path to filemimeType- File MIME typefileSize- File size in bytesmd5Hash- MD5 hash of file contentsha1Hash- SHA1 hash of file contentcreateTime- Upload timestampupdateTime- Last update timestampmetadata- JSON field for additional datastorageType- Storage backend type (default: local)isActive- Soft delete flaguserId- User ID for member uploads (null for anonymous)
FileType Entity
name- Display name (e.g., "JPEG Image")mimeType- MIME type (e.g., "image/jpeg")extension- File extension (e.g., "jpg")maxSize- Maximum file size in bytesuploadType- Who can upload ('anonymous', 'member', 'both')isActive- Whether this type is enabledcreateTime- Creation timestampupdateTime- Last update timestamp
Security
Access Control
- Anonymous uploads have separate endpoints and permissions
- Member uploads require authentication
- File types can be restricted by upload type (anonymous/member/both)
- File size limits are enforced per file type
Data Protection
- File hashes (MD5, SHA1) are calculated for integrity verification
- Files are stored with unique generated names to prevent collisions
- Original filenames are preserved in the database
- User tracking for authenticated uploads
- IP address tracking for security auditing
Best Practices
- Always validate file types on the server side
- Set appropriate file size limits
- Regularly clean up anonymous files
- Monitor file statistics for unusual activity
- Use HTTPS for file uploads
- Consider implementing virus scanning for uploaded files
Dependencies
This bundle requires:
- PHP ^8.1
- Symfony ^6.4
- Doctrine ORM ^2.0 || ^3.0
- League Flysystem ^3.0
- Symfony String Component
Bundle dependencies:
tourze/doctrine-ip-bundletourze/doctrine-timestamp-bundletourze/doctrine-track-bundletourze/doctrine-user-bundletourze/doctrine-snowflake-bundle
Advanced Usage
Event Listeners
You can listen to file upload events:
namespace App\EventListener; use Tourze\FileStorageBundle\Event\FileUploadedEvent; use Symfony\Component\EventDispatcher\Attribute\AsEventListener; #[AsEventListener(event: FileUploadedEvent::class)] class FileUploadListener { public function __invoke(FileUploadedEvent $event): void { $file = $event->getFile(); // Custom logic: virus scan, image optimization, etc. } }
Custom File Validators
Extend the validation logic:
namespace App\Validator; use Symfony\Component\HttpFoundation\File\UploadedFile; use Tourze\FileStorageBundle\Validator\FileValidatorInterface; class VirusScanValidator implements FileValidatorInterface { public function validate(UploadedFile $file): void { // Implement virus scanning logic if ($this->hasVirus($file)) { throw new FileValidationException('File contains malware'); } } }
Testing
The bundle includes comprehensive tests with full coverage:
# Run all tests ./vendor/bin/phpunit packages/file-storage-bundle/tests # Run with coverage ./vendor/bin/phpunit packages/file-storage-bundle/tests --coverage-html coverage
Test Suite Results:
- 📊 128 tests, 424 assertions
- ✅ All tests passing
- 🧪 100% test coverage for critical components
- 🎯 Unit + Integration tests for controllers, services, repositories, and commands
PHPStan Analysis
Static analysis with PHPStan level 5:
php -d memory_limit=2G ./vendor/bin/phpstan analyse packages/file-storage-bundle
Analysis Results:
- ✅ 0 errors - Clean code with proper type declarations
- 🔒 Level 5 - Strict type checking enabled
- 📝 Full documentation - All public methods documented
License
This bundle is released under the MIT License. See the LICENSE file for details.
统计信息
- 总下载量: 1.11k
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 0
- 依赖项目数: 9
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2025-11-01