tiloweb/uploaded-file-type-bundle
A Symfony bundle for detecting and validating the file type of uploads. Inspect MIME types and extensions to verify incoming files, reject unexpected formats, and keep upload handling safe and consistent across your application.
Read this first: this is a Symfony bundle, not a Laravel package. tiloweb/uploaded-file-type-bundle has no service provider, no facade, no config/uploaded-file-type.php to publish. It ships a Symfony form type and is registered via config/bundles.php. If you are evaluating it for a Laravel app, stop here — the useful outcome is borrowing the pattern, not the dependency.
For a Symfony app:
composer require tiloweb/uploaded-file-type-bundle:^1.0
On PHP 7.4 or Symfony 5/6 you will resolve to v1.0.2, which is still fine but is the pre-PHP-8 branch.config/bundles.php if Flex didn't do it:
Tiloweb\UploadedFileTypeBundle\UploadedFileTypeBundle::class => ['all' => true],
vendor/tiloweb/uploaded-file-type-bundle/ — read README.md, then the Form/Type/ directory for the exact FQCN of the type, then Tests/ for the most authoritative usage examples. The bundle is small; reading the whole source takes ten minutes and beats guessing at the API.PostType/UserType with an avatar or attachment field, where you want $form->handleRequest() + $form->isValid() to hand you a usable file rather than you wiring the move logic by hand in every controller.Form-level usage. The bundle's whole value proposition is that the field behaves like a first-class form type. Drop it into a FormType in place of the stock FileType:
$builder->add('attachment', UploadedFileType::class, [
'required' => false,
'constraints' => [
new File(['maxSize' => '4M']),
new MimeType(['mimeTypes' => ['application/pdf']]),
],
]);
The two-property entity pattern is what you'll actually ship, regardless of what the bundle does internally. Keep the UploadedFile on a non-persisted property (#[ORM\Column] on nothing, and 'mapped' => false if the form type doesn't handle it), and store a string path/name on the entity. Move the file after isValid(), not during binding:
if ($form->isSubmitted() && $form->isValid()) {
$file = $form->get('attachment')->getData();
$name = bin2hex(random_bytes(8)).'.'.$file->guessExtension();
$file->move($this->getParameter('kernel.project_dir').'/var/uploads', $name);
$entity->setAttachment($name);
}
Validate with Symfony's constraints, not with if statements. File, Image, MimeType, FileValidator all operate on UploadedFile and produce form errors against the field. This is the part Laravel devs under-use: $request->validate(['avatar' => 'image|max:4096']) has a direct analogue, but attaching constraints to the form field keeps the error rendering free.
Rendering. Use form_row(form.attachment) as normal. Set enctype="multipart/form-data" on the <form> — a missing enctype produces an empty $_FILES and a silently null field, which reads like a bundle bug and isn't. Add an accept attribute for UX but never rely on it.
If you need lifecycle automation (delete old file on replace, cascade on entity delete), VichUploaderBundle is the mature option and pairs fine with this type. Don't hand-roll cleanup callbacks in five entities; write one subscriber.
Testing. Build the file with new UploadedFile($path, 'x.pdf', 'application/pdf', null, true) — the true test-mode flag skips the is-uploaded check. Submit the form via KernelBrowser::submit() and assert on the moved file's existence in a var/uploads test directory.
Laravel translation of the pattern, if that's your actual stack: the equivalent day-to-day flow is $path = $request->file('avatar')->store('avatars', 'public') plus Storage::url($path) and a 'image|max:4096' rule. The bundle's advantage in Symfony is form-type integration and constraint-driven errors; Laravel gets that from the validator and Storage facade already, so there's little to port beyond the naming convention.
composer require will downgrade to v1.0.2 or fail — use composer why-not tiloweb/uploaded-file-type-bundle 1.0.3 to see the blocking constraint instead of guessing.SYMFONY_DEPRECATIONS_HELPER=max[direct]=0, the pre-1.0.3 versions will fail the build on SF7 even though they "work". Pin ^1.0.3 explicitly rather than ^1.0.ServiceProvider, not in the Laravel package registry, no config/ to publish. Any attempt to composer require it into a Laravel app will install dead weight or fail on symfony/form version conflicts.php.ini limits fail silently. upload_max_filesize and post_max_size being exceeded gives you a null file or a request with empty $_FILES, not an exception. If a large upload "doesn't arrive", check phpinfo() before you check the bundle.move() overwrites without warning. Always generate a unique target name (random_bytes, uuid, or uniqid). Two users uploading avatar.jpg will otherwise clobber each other.move() to a non-existent directory throws; var/ permissions differ between your host and the PHP-FPM user in Docker. Create the directory in a deploy step.bin/console debug:form (it lists available types and their options) rather than assuming. debug:container --tag=form.type also works.FormTypeExtension to add options globally → validation constraints → a Twig form theme block if you need custom markup → finally, subclassing the type. Subclassing is the least stable against minor releases.Tests/ directory for the intended API before assuming an option name.How can I help you explore Laravel packages today?