netbull / media-bundle
Media bundle
Requires
- php: >=8.3
- ext-curl: *
- ext-exif: *
- ext-gd: *
- aws/aws-sdk-php: 3.*
- doctrine/collections: ^2.1
- doctrine/dbal: ^3.7|^4.0
- doctrine/doctrine-bundle: ^2.12|^3.0
- doctrine/orm: ^2.20|^3.0
- doctrine/persistence: ^3.1|^4.0
- imagine/imagine: 1.*
- knplabs/gaufrette: 0.9.*
- psr/log: ^3.0
- symfony/config: 7.4.*
- symfony/console: 7.4.*
- symfony/dependency-injection: 7.4.*
- symfony/event-dispatcher: 7.4.*
- symfony/form: 7.4.*
- symfony/framework-bundle: 7.4.*
- symfony/http-client: 7.4.*
- symfony/http-foundation: 7.4.*
- symfony/http-kernel: 7.4.*
- symfony/mime: 7.4.*
- symfony/options-resolver: 7.4.*
- symfony/process: 7.4.*
- symfony/routing: 7.4.*
- symfony/security-bundle: 7.4.*
- symfony/security-core: 7.4.*
- symfony/twig-bundle: 7.4.*
- symfony/yaml: 7.4.*
- twig/twig: ^3.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.64
- phpstan/phpstan: ^2.0
- phpunit/phpunit: ^11.0
- symfony/messenger: 7.4.*
Suggests
- symfony/messenger: Enables asynchronous thumbnail generation (netbull_media.thumbnail.async)
- dev-master
- v7.2.9
- v7.2.8
- v7.2.7
- v7.2.6
- v7.2.5
- v7.2.4
- v7.2.3
- v7.2.2
- v7.2.1
- v7.2.0
- v7.1.2
- v7.1.1
- v7.1.0
- v7.0.10
- v7.0.9
- v7.0.8
- v7.0.7
- v7.0.6
- v7.0.5
- v7.0.4
- v7.0.3
- v7.0.2
- v7.0.1
- v7.0.0
- 6.x-dev
- v6.4.15
- v6.4.14
- v6.4.13
- v6.4.12
- v6.4.11
- v6.4.10
- v6.4.9
- v6.4.8
- v6.4.7
- v6.4.6
- v6.4.5
- v6.4.4
- v6.4.3
- v6.4.2
- v6.4.1
- v6.4.0
- v6.3.0
- v6.2.0
- v6.1.6
- v6.1.5
- v6.1.4
- v6.1.3
- v6.1.2
- v6.1.1
- v6.1.0
- v6.0.2
- v6.0.1
- v6.0.0
- 5.x-dev
- v5.5.9
- v5.5.8
- v5.5.7
- v5.5.6
- v5.5.5
- v5.5.4
- v5.5.3
- v5.5.2
- v5.5.1
- v5.5.0
- v5.4.3
- v5.4.2
- v5.4.1
- v5.4.0
- v5.2.8
- v5.2.7
- v5.2.6
- v5.2.5
- v5.2.4
- v5.2.3
- v5.2.2
- v5.2.1
- v5.2.0
- v5.1.4
- v5.1.3
- v5.1.2
- v5.1.1
- v5.1.0
- v5.0.1
- v5.0.0
- 4.x-dev
- v4.4.11
- v4.4.10
- v4.4.9
- v4.4.8
- v4.4.7
- v4.4.6
- v4.4.5
- v4.4.4
- v4.4.3
- v4.4.2
- v4.4.1
- v4.4.0
- v2.3.1
- v2.3.0
- v2.2.5
- v2.2.4
- v2.2.3
- v2.2.2
- v2.2.1
- v2.2.0
- v2.1.32
- v2.1.31
- v2.1.30
- v2.1.29
- v2.1.28
- v2.1.27
- v2.1.26
- v2.1.25
- v2.1.24
- v2.1.23
- v2.1.22
- v2.1.21
- v2.1.20
- v2.1.19
- v2.1.18
- v2.1.17
- v2.1.16
- v2.1.15
- v2.1.14
- v2.1.13
- v2.1.12
- v2.1.11
- v2.1.10
- v2.1.9
- v2.1.8
- v2.1.7
- v2.1.6
- v2.1.5
- v2.1.4
- v2.1.3
- v2.1.2
- v2.1.1
- v2.1.0
- v2.0.12
- v2.0.11
- v2.0.10
- v2.0.9
- v2.0.8
- v2.0.7
- v2.0.6
- v2.0.5
- v2.0.4
- v2.0.3
- v2.0.2
- v2.0.1
- dev-fix/p0-security-and-bugs
This package is auto-updated.
Last update: 2026-06-05 08:26:47 UTC
README
A Symfony bundle for managing media — images, files and video providers (YouTube, Vimeo, Youku) — with pluggable storage (local filesystem or Amazon S3), thumbnail generation and configurable access-control strategies for downloads/views. Originally a trimmed fork of SonataMediaBundle.
- PHP: >= 8.3
- Symfony: 7.4 (LTS)
Installation
composer require netbull/media-bundle
Register the bundle
With Symfony Flex this is automatic. Otherwise add it to config/bundles.php:
return [ // ... NetBull\MediaBundle\NetBullMediaBundle::class => ['all' => true], ];
Import the routes
The download/view endpoints live in the bundle. Add to config/routes.yaml:
netbull_media: resource: '@NetBullMediaBundle/config/routes.yaml'
This registers netbull_media_view (/media/view/{id}/{format}) and
netbull_media_download (/media/download/{id}/{format}).
Configuration
Create config/packages/netbull_media.yaml. A minimal local-development setup:
netbull_media: default_context: default filesystem: local: directory: '%kernel.project_dir%/public/uploads/media' create: true cdn: server: path: /uploads/media contexts: default: providers: - netbull_media.provider.image formats: thumb: { width: 150, height: 150 } normal: { width: 600 }
Each context declares which providers it accepts, its image formats, and the
download/view security strategy. See docs/example_config.yaml
for a full, annotated example (multiple contexts, S3, signed URLs, custom strategies).
Available services
| Kind | Service id |
|---|---|
| Providers | netbull_media.provider.image, .file, .youtube, .vimeo, .youku |
| Filesystems | netbull_media.filesystem.local, netbull_media.filesystem.s3 |
| CDN | netbull_media.cdn.server, netbull_media.cdn.local.server |
| Security strategies | netbull_media.security.public_strategy, .forbidden_strategy, .superadmin_strategy, .connected_strategy, .hash_strategy |
Upload restrictions — each provider's
allowed_extensions/allowed_mime_typesare enforced on upload using the file's sniffed content (not the client-supplied name/type). A file is accepted only if it matches at least one of the configured lists.
S3 ACL — default to
acl: privateand serve public assets through the CDN; apublic-readACL makes objects world-readable and bypasses the bundle's download/view security strategies.
Secured downloads — for contexts behind a download/view security strategy, S3-backed media is served by redirecting to a short-lived (300s) pre-signed S3 URL, so the file streams S3 → client and never passes through PHP. Local storage streams the file in chunks. Either way the access-control check runs in the controller before the response is issued.
Video providers (SSRF) — video providers fetch oEmbed metadata and remote thumbnails over HTTP. Thumbnail URLs are validated before fetching (http/https to public hosts only; private, loopback and cloud-metadata addresses are refused) and redirects are disabled. To route this egress through your own controls, enable
framework.http_clientand the bundle will use the configured client.
Thumbnail generation (sync or async)
By default thumbnails are generated in-process when the media is flushed. To offload resizing to a worker, enable the async strategy:
netbull_media: thumbnail: async: true
Optional dependency — async mode needs the Messenger component, which the bundle treats as an optional (suggested) dependency. Install it before enabling async:
composer require symfony/messengerThe message handler is only registered when
symfony/messengeris installed, and enablingthumbnail.async: truewithout it fails fast with a clear error at container compile time. In the default sync mode the bundle works without Messenger.
When async: true, the bundle dispatches a
NetBull\MediaBundle\Message\GenerateThumbnailMessage per format to the Messenger bus. Route it to
an async transport so a worker does the resizing (worker recycling provides the memory isolation
that long-running image processing needs):
# config/packages/messenger.yaml framework: messenger: transports: async: '%env(MESSENGER_TRANSPORT_DSN)%' routing: NetBull\MediaBundle\Message\GenerateThumbnailMessage: async
php bin/console messenger:consume async --memory-limit=256M
With no transport routing configured, Messenger handles the message synchronously, so async mode is safe to enable before you have a worker.
Usage
Attach media to your entity
The bundle ships a mapped NetBull\MediaBundle\Entity\Media entity — reference it from your own
entities:
use Doctrine\ORM\Mapping as ORM; use NetBull\MediaBundle\Entity\Media; #[ORM\ManyToOne(targetEntity: Media::class, cascade: ['persist', 'remove'])] private ?Media $image = null;
Upload
Set the binary content and the provider/context, then persist. The bundle's Doctrine listener transforms the upload, stores it and generates thumbnails on flush:
$media = new Media(); $media->setContext('default'); $media->setProviderName('netbull_media.provider.image'); $media->setBinaryContent($uploadedFile); // Symfony UploadedFile / SplFileInfo / path $em->persist($media); $em->flush();
In forms, use NetBull\MediaBundle\Form\Type\MediaType (or MediaShortType) with the provider
and context options.
Render in Twig
The bundle registers these Twig filters:
{# Public URL for a format #} <img src="{{ media|path('normal') }}"> {# Signed (access-controlled) URL — image/file providers #} <img src="{{ media|secure_path(user_identifier, 'normal') }}"> {# Rendered <img>/thumbnail markup #} {{ media|thumbnail('thumb') }} {# Rendered provider view (image tag, video embed, file link) #} {{ media|view('normal') }}
Autowiring
use NetBull\MediaBundle\Provider\PoolInterface; use NetBull\MediaBundle\Signature\SignatureHasherInterface; public function __construct( private PoolInterface $pool, private SignatureHasherInterface $signatureHasher, ) {}
Console commands
| Command | Description |
|---|---|
netbull:media:create-thumbnail <id> [format] |
Generate a thumbnail for one media |
netbull:media:resize [context] |
Generate missing thumbnails |
netbull:media:sync-thumbnails |
Regenerate thumbnails |
netbull:media:clone <id> |
Clone a media (and its stored file) |
Development
composer test # PHPUnit composer phpstan # static analysis composer cs-check # coding standards (php-cs-fixer, dry-run) composer check # all of the above