PHPackages                             tourze/file-storage-bundle - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. tourze/file-storage-bundle

ActiveSymfony-bundle

tourze/file-storage-bundle
==========================

Symfony bundle for file storage management with upload, validation, and cleanup features

1.1.0(4mo ago)01.1k6MITPHPCI failing

Since Nov 1Pushed 4mo agoCompare

[ Source](https://github.com/tourze/file-storage-bundle)[ Packagist](https://packagist.org/packages/tourze/file-storage-bundle)[ RSS](/packages/tourze-file-storage-bundle/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (4)Dependencies (54)Versions (5)Used By (6)

File Storage Bundle
===================

[](#file-storage-bundle)

[English](README.md) | [中文](README.zh-CN.md)

[![PHP Version](https://camo.githubusercontent.com/acffb6ae1962992d26e4466782832787e79504a6250f80d732c4283458b9f497/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d253545382e312d626c75652e737667)](https://www.php.net/)[![License](https://camo.githubusercontent.com/8bb50fd2278f18fc326bf71f6e88ca8f884f72f179d3e555e20ed30157190d0d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d677265656e2e737667)](LICENSE)

[![Build Status](https://camo.githubusercontent.com/310d67bb18e86887611db0b03a76e36393d4610e987bfb40128e3c0c2275c535/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f776f726b666c6f772f7374617475732f746f75727a652f66696c652d73746f726167652d62756e646c652f4349)](https://github.com/tourze/file-storage-bundle/actions)

[![Code Coverage](https://camo.githubusercontent.com/a36904a094ff099776c5b8bec3082fee4754701fe0bf564bf23ec26e1a4c036a/68747470733a2f2f696d672e736869656c64732e696f2f636f6465636f762f632f6769746875622f746f75727a652f66696c652d73746f726167652d62756e646c65)](https://codecov.io/gh/tourze/file-storage-bundle)

Symfony Bundle for file upload and storage management with Flysystem integration.

Table of Contents
-----------------

[](#table-of-contents)

- [Features](#features)
- [Installation](#installation)
- [Configuration](#configuration)
- [Database Setup](#database-setup)
- [Usage](#usage)
    - [Anonymous Upload](#anonymous-upload)
    - [Member Upload](#member-upload)
    - [Get Allowed File Types](#get-allowed-file-types)
- [File Type Management](#file-type-management)
- [Console Commands](#console-commands)
    - [Clean Anonymous Files](#clean-anonymous-files)
    - [Delete Files](#delete-files)
    - [Cron Job Example](#cron-job-example)
- [Advanced Storage Configuration](#advanced-storage-configuration)
    - [Custom Storage Adapter](#custom-storage-adapter)
- [Entity Structure](#entity-structure)
    - [File Entity](#file-entity)
    - [FileType Entity](#filetype-entity)
- [Security](#security)
- [Dependencies](#dependencies)
- [Advanced Usage](#advanced-usage)
- [Testing](#testing)
- [License](#license)

Features
--------

[](#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
------------

[](#installation)

```
composer require tourze/file-storage-bundle
```

Configuration
-------------

[](#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
--------------

[](#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
-----

[](#usage)

### Anonymous Upload

[](#anonymous-upload)

```
POST /api/files/upload/anonymous
Content-Type: multipart/form-data

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

[](#member-upload)

```
POST /api/files/upload/member
Authorization: Bearer
Content-Type: multipart/form-data

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

[](#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-file-info)

```
GET /api/files/{id}
```

File Type Management
--------------------

[](#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
----------------

[](#console-commands)

### Clean Anonymous Files

[](#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-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

[](#cron-job-example)

Add to your crontab to run every hour:

```
0 * * * * cd /path/to/project && bin/console file-storage:clean-anonymous
```

#### File Statistics

[](#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
------------------------------

[](#advanced-storage-configuration)

The bundle uses Flysystem for file storage abstraction. By default, it uses a local filesystem adapter.

### Custom Storage 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
----------------

[](#entity-structure)

### File Entity

[](#file-entity)

- `originalName` - Original uploaded filename
- `fileName` - Generated unique filename
- `filePath` - Relative path to file
- `mimeType` - File MIME type
- `fileSize` - File size in bytes
- `md5Hash` - MD5 hash of file content
- `sha1Hash` - SHA1 hash of file content
- `createTime` - Upload timestamp
- `updateTime` - Last update timestamp
- `metadata` - JSON field for additional data
- `storageType` - Storage backend type (default: local)
- `isActive` - Soft delete flag
- `userId` - User ID for member uploads (null for anonymous)

### FileType Entity

[](#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 bytes
- `uploadType` - Who can upload ('anonymous', 'member', 'both')
- `isActive` - Whether this type is enabled
- `createTime` - Creation timestamp
- `updateTime` - Last update timestamp

Security
--------

[](#security)

### Access Control

[](#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

[](#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

[](#best-practices)

1. Always validate file types on the server side
2. Set appropriate file size limits
3. Regularly clean up anonymous files
4. Monitor file statistics for unusual activity
5. Use HTTPS for file uploads
6. Consider implementing virus scanning for uploaded files

Dependencies
------------

[](#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-bundle`
- `tourze/doctrine-timestamp-bundle`
- `tourze/doctrine-track-bundle`
- `tourze/doctrine-user-bundle`
- `tourze/doctrine-snowflake-bundle`

Advanced Usage
--------------

[](#advanced-usage)

### Event Listeners

[](#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

[](#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
-------

[](#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

[](#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
-------

[](#license)

This bundle is released under the MIT License. See the [LICENSE](LICENSE) file for details.

###  Health Score

37

—

LowBetter than 82% of packages

Maintenance79

Regular maintenance activity

Popularity14

Limited adoption so far

Community13

Small or concentrated contributor base

Maturity38

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~16 days

Total

4

Last Release

139d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/e354fdb316da535dfa8ba2e9193a473c403b6bc6fb9170778d1dc50e304c6e9d?d=identicon)[tourze](/maintainers/tourze)

---

Top Contributors

[![tourze](https://avatars.githubusercontent.com/u/13899502?v=4)](https://github.com/tourze "tourze (1 commits)")

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/tourze-file-storage-bundle/health.svg)

```
[![Health](https://phpackages.com/badges/tourze-file-storage-bundle/health.svg)](https://phpackages.com/packages/tourze-file-storage-bundle)
```

###  Alternatives

[sylius/sylius

E-Commerce platform for PHP, based on Symfony framework.

8.4k5.6M647](/packages/sylius-sylius)[contao/core-bundle

Contao Open Source CMS

1231.6M2.3k](/packages/contao-core-bundle)[sulu/sulu

Core framework that implements the functionality of the Sulu content management system

1.3k1.3M151](/packages/sulu-sulu)[ec-cube/ec-cube

EC-CUBE EC open platform.

78527.0k1](/packages/ec-cube-ec-cube)[prestashop/prestashop

PrestaShop is an Open Source e-commerce platform, committed to providing the best shopping cart experience for both merchants and customers.

9.0k15.4k](/packages/prestashop-prestashop)[open-dxp/opendxp

Content &amp; Product Management Framework (CMS/PIM)

7310.3k29](/packages/open-dxp-opendxp)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
