tourze / file-storage-bundle
Symfony bundle for file storage management with upload, validation, and cleanup features
Installs: 61
Dependents: 6
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
Type:symfony-bundle
pkg:composer/tourze/file-storage-bundle
Requires
- ext-reflection: *
- ext-spl: *
- doctrine/collections: ^2.3
- doctrine/data-fixtures: ^2.0
- 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
- monolog/monolog: ^3.1
- psr/log: ^3|^2|^1
- symfony/config: ^7.3
- symfony/console: ^7.3
- symfony/dependency-injection: ^7.3
- symfony/doctrine-bridge: ^7.3
- symfony/event-dispatcher: ^7.3
- symfony/form: ^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/security-bundle: ^7.3
- symfony/security-core: ^7.3
- symfony/security-http: ^7.3
- symfony/string: ^7.3
- symfony/validator: ^7.3
- symfony/yaml: ^7.3
- tourze/access-token-bundle: 1.0.*
- tourze/arrayable: 1.*
- tourze/bundle-dependency: 1.*
- tourze/doctrine-indexed-bundle: 1.0.*
- tourze/doctrine-ip-bundle: 1.0.*
- tourze/doctrine-snowflake-bundle: 1.0.*
- tourze/doctrine-timestamp-bundle: 1.0.*
- tourze/doctrine-track-bundle: 1.0.*
- tourze/doctrine-user-bundle: 1.0.*
- tourze/easy-admin-image-preview-field-bundle: 1.0.*
- tourze/easy-admin-menu-bundle: 1.0.*
- tourze/symfony-cron-job-bundle: 1.0.*
- tourze/symfony-dependency-service-loader: 1.*
- tourze/symfony-routing-auto-loader-bundle: 1.0.*
Requires (Dev)
This package is auto-updated.
Last update: 2025-11-02 05:56:35 UTC
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
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); } }
Then override the factory service in your application:
# config/services.yaml services: Tourze\FileStorageBundle\Factory\FilesystemFactory: class: App\Factory\S3FilesystemFactory arguments: $s3Client: '@aws.s3.client' $bucket: '%env(S3_BUCKET)%'
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.