Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

All about Uploading Files in Symfony


What you'll be learning

This tutorial is built on Symfony 4 but works great in Symfony 5!
// composer.json
    "require": {
        "php": "^7.1.3",
        "ext-iconv": "*",
        "aws/aws-sdk-php": "^3.87", // 3.87.10
        "composer/package-versions-deprecated": "^1.11", // 1.11.99
        "knplabs/knp-markdown-bundle": "^1.7", // 1.7.1
        "knplabs/knp-paginator-bundle": "^2.7", // v2.8.0
        "knplabs/knp-time-bundle": "^1.8", // 1.9.0
        "league/flysystem-aws-s3-v3": "^1.0", // 1.0.22
        "league/flysystem-cached-adapter": "^1.0", // 1.0.9
        "liip/imagine-bundle": "^2.1", // 2.1.0
        "nexylan/slack-bundle": "^2.0,<2.2.0", // v2.1.0
        "oneup/flysystem-bundle": "^3.0", // 3.0.3
        "php-http/guzzle6-adapter": "^1.1", // v1.1.1
        "sensio/framework-extra-bundle": "^5.1", // v5.2.4
        "stof/doctrine-extensions-bundle": "^1.3", // v1.3.0
        "symfony/asset": "^4.0", // v4.2.3
        "symfony/console": "^4.0", // v4.2.3
        "symfony/flex": "^1.9", // v1.17.6
        "symfony/form": "^4.0", // v4.2.3
        "symfony/framework-bundle": "^4.0", // v4.2.3
        "symfony/orm-pack": "^1.0", // v1.0.6
        "symfony/security-bundle": "^4.0", // v4.2.3
        "symfony/serializer-pack": "^1.0", // v1.0.2
        "symfony/twig-bundle": "^4.0", // v4.2.3
        "symfony/validator": "^4.0", // v4.2.3
        "symfony/web-server-bundle": "^4.0", // v4.2.3
        "symfony/yaml": "^4.0", // v4.2.3
        "twig/extensions": "^1.5" // v1.5.4
    "require-dev": {
        "doctrine/doctrine-fixtures-bundle": "^3.0", // 3.1.0
        "easycorp/easy-log-handler": "^1.0.2", // v1.0.7
        "fzaninotto/faker": "^1.7", // v1.8.0
        "symfony/debug-bundle": "^3.3|^4.0", // v4.2.3
        "symfony/dotenv": "^4.0", // v4.2.3
        "symfony/maker-bundle": "^1.0", // v1.11.3
        "symfony/monolog-bundle": "^3.0", // v3.3.1
        "symfony/phpunit-bridge": "^3.3|^4.0", // v4.2.3
        "symfony/profiler-pack": "^1.0", // v1.0.4
        "symfony/var-dumper": "^3.3|^4.0" // v4.2.3

Need to upload some files in Symfony? Excellent! You've come to the right place!

These days, uploading files can be simple... or incredibly complex - with cloud storage, private files, thumbnailing, validation and so much more. So let's tackle... all of it!

  • Understanding basic file uploading
  • File uploads in a Symfony form
  • File (and Image) validation
  • Naming files (unique vs keeping the original name... or both?)
  • Handling/moving uploaded files in an organized way
  • Rendering links to the uploaded files
  • Thumbnailing with LiipImagineBundle
  • "Uploading" files in your data fixtures
  • Flysystem: using a filesystem abstraction
  • Uploading files but keeping them private
  • Adding a download endpoint for "private" files
  • Fancy AJAX uploading with Dropzone
  • Storing files in the cloud (S3)

So get into the (Drop)zone and let us upload some serious knowledge to you in this... multipart(.../form-data) tutorial. Ok... better jokes are inside... I promise!

Your Guides

Ryan Weaver

Buy Access
Login or register to track your progress!

Join the Conversation?

Login or Register to join the conversation
Lijana Z. Avatar
Lijana Z. Avatar Lijana Z. | posted 3 years ago

Looks like so much videos for seemingly simple stuff. But I remember when was working with file uploads, not only with symfony but with zend 1 also, maybe some other framework, there have been various problems, and you think - damn this is just file upload, why I am taking that long to fix it :) I remember colleague also frontender said - when he sees task with file upload, he tries to not take it if somebody else can :D

I remember there was an issue when the application was running somehow on several servers and problem was something like when application called from one server it sees the uploaded file, but when from another it does not see. And it looked like random bug and annoying until we found that file lies in one server, and if user request goes to that server, it goes ok, but if request goes to another server - no file. And also I was not responsible for the servers infrastructure, so I did not even think about that. There was a devops guy working on this. And yea, probably it was working find on my machine :D because it always was one server :) maybe the correct way should be to have locally few docker containers of php running to notice this early while developing?

1 Reply

Haha, I couldn’t agree more :p. File uploads... so simple right? Well... it can be... but it can quickly get complicated!

And yea... with multiple servers, a lot can get weird if you’re not careful... like session storage or uploads. If you DO know you’ll have this setup, I guess imitating it locally with Docker might be a good idea... I mean local dev env as close to production is always a good thing to go for :).


Peter K. Avatar
Peter K. Avatar Peter K. | posted 3 years ago

I would like to suggest multiple file upload

1 Reply

Hey Peter K.!

It's actually a topic that I (so far) have been purposely avoiding in this tutorial. But let me explain - and then you can tell me if you disagree (because ultimately, people *are* asking for this, and the tutorial needs to cover all the stuff that people really need). Instead of true multiple file uploads, I much prefer a JavaScript approach - and we WILL cover this in the tutorial. For example, Dropzone allows you to select multiple files and they are both uploaded instantly. Well, *technically*, they are uploaded on two separate requests - so one file per request. But it accomplishes what a user needs: allowing you to upload multiple files at once. It's also a better user experience in my opinion, because the uploads have a progress bar, happen via AJAX, and you don't need to wait until you finish filling out the whole form before you submit (and then, if you have a validation error, the file uploads are lost).

So, would that approach solve what you're looking for? Or is there something specific about native multiple file uploads?

Thanks for the feedback!

6 Reply
Mixa S. Avatar
Mixa S. Avatar Mixa S. | posted 3 years ago

Hello symfonycasts team!
Will you cover edit/delete options when uploading multiple files?

1 Reply

Hey Mixa S.!

Maybe... ;)

Can you explain a bit more? What do you mean by "uploading multiple files" - are you building a form where you have multiple file upload inputs and you handle them all at once when you submit the form? Or do you have some JavaScript where you want to allow the user to, for example, drop one file and have it upload, then drop another file and have it upload (where each 1 upload is technically its own 1 request, but you could do multiple at a time)?

And what do you mean by edit? If I upload a PDF... editing it would really mean deleting it and uploading a new one, right? Basically, describe the feature you're dreaming up - I definitely want to make sure it's included.


2 Reply
Mixa S. Avatar
Mixa S. Avatar Mixa S. | weaverryan | posted 3 years ago | edited

Hey weaverryan!
Example: user drops files and wants to change their sequence (position). For instance, make the last one - the first or something.
Or open record (image gallery) containing images and delete one image and upload two more then save the record.
Or change image (file) name in the gallery.
I am thinking of embedded form collection , it can be pain-point.


Hey Mixa S.!

Thanks for sharing :). One more question: What do you mean exactly by an "image gallery". I've had a few people as about this - but it can mean a lot of different things. For example, you could build a "widget" that allows you to randomly upload any image to your system, search, delete, etc - all from within maybe even a JS "modal". And you might even find some third-party JS library for this and then try to integrate it into Symfony. Or, you might just mean "When I am editing a Product, I am able to see all the photos for that product on that form, and am able to re-order, delete, upload more, rename, etc".


1 Reply
Mixa S. Avatar

Hi weaverryan!

I mean exact as you mentioned:

"When I am editing a Product, I am able to see all the photos for that
product on that form, and am able to re-order, delete, upload more,
rename, etc"

Will something like that be in this course?


Hey Mixa S.!

Got it! Most was already in there - but I'm going to make sure this is all in there. For this part, it will probably be a list of "documents" (e.g. PDF, doc, images, whatever you want) that we will re-order, delete, rename, etc. I don't think it makes much difference - we'll just render the filename and a link to download it instead of an img tag (we will cover some image-specific things in another part of the tutorial).


2 Reply
Krzysztof K. Avatar
Krzysztof K. Avatar Krzysztof K. | posted 3 years ago

Ryan! When? :D And Please add breadcrumbs to SymfonyCasts, because at the moment navigation is a bit painful...

1 Reply

Thanks for the feedback Krzysztof K. we'll look into that! And this course will start releasing next week :)

1 Reply
Rufnex Avatar

Does this work also in SF 6?


Hey Rufnex,

Yes, all the concepts in this tutorial are still relevant, however, you may find a few deprecations here and there, and you may find small differences on how to configure something


1 Reply
Kiuega Avatar

Hello ! I just finished the training! Great (although it took some tweaking to make it work with the latest versions). However, one problem remains in force.

LiipImagineBundle does not delete files that we have stored on AWS S3.

In fact, the main image is well replaced on S3, but not in the liipImagineBundle thumbnails directory. How could we fix this?


Hey Kiuega!

Yes! Nice job navigating the version changes - sorry about that - I've had a long-standing issue to get some notes added to this tutorial!

> LiipImagineBundle does not delete files that we have stored on AWS S3.
> In fact, the main image is well replaced on S3, but not in the liipImagineBundle thumbnails directory. How could we fix this?

Let me me make sure I understand: are you referring to, if you delete an image, the related thumbnail is not being deleted? If so, if I remember correctly, that's simply not something that we addressed in this tutorial. Is that accurate?

If so, I think you'd need to write custom code for that. There's actually a good-looking example here of using one of the Liip services to help with this: https://stackoverflow.com/q...


1 Reply
Kiuega Avatar
Kiuega Avatar Kiuega | weaverryan | posted 1 year ago | edited

Hello @weaverryan :)

>Let me me make sure I understand: are you referring to, if you delete an image, the related thumbnail is not being deleted? If so, if I remember correctly, that's simply not something that we addressed in this tutorial. Is that accurate?

Thank you for the link ! In the end I opted for a slightly more brutal solution (but which works perfectly so why not). In the UploaderHelper class, when deleting file, I just use this line :

$this->cache->remove($path); (where $path is the path of the file to delete), from the \Liip\ImagineBundle\Imagine\Cache\CacheManager class.

It will delete the file for all filters where it is ! :)

Kiuega Avatar

Hello, is this tutorial can be for Symfony 5 (with same code) with PHP 8 ? Do you recommend a bundle that would do absolutely everything we do in this tutorial, without having to code everything ourselves, but for the same result?


Hey Kiuega,

> is this tutorial can be for Symfony 5 (with same code) with PHP 8 ?

Thank you for your interest in SymfonyCasts tutorials! Unfortunately, download code of this course is not compatible with PHP 8, dependencies are locked on PHP ^7.1. So, if you want to follow this course - the easiest way would be to downgrade your PHP version to 7.4 at least (or install a legacy PHP version, i.e. you will have a few versions of PHP on your machine, e.g. 7.4 and 8).

But if still you want to follow this tutorial on PHP 8 - you can do it, but you would need to upgrade Composer dependencies first to versions that support PHP 8. Or, if you already have your own project - you can try to apply changes we show in this course to your own project.

If you ever have any issues or get stuck following this tutorial on a newer version of Symfony - just let us know in the comments and we will help you!

> Do you recommend a bundle that would do absolutely everything we do in this tutorial, without having to code everything ourselves, but for the same result?

Well, I don't think there's a bundle that would do *absolutely everything* we show in this course, at least I don't know such bundle :) But, there's a few good bundles I could recommend you to look at:
- https://github.com/dustin10...
- https://github.com/1up-lab/...

They both are popular solutions that work with uploads. IIRC VichUploaderBundle is a plain PHP solution, but OneupUploaderBundle has some integration with JS libraries to make the UX more nicer.

I hope this helps!


Fabrice Avatar

Thank you very much for this answer ! I will create a new Symfony PHP 8 project and test the course ! :D


Hey Kiuega,

Great :) If you will get stuck following this course on this project based on a newer version of Symfony and PHP - let us know in the comments, we will try to help!


1 Reply
Christina V. Avatar
Christina V. Avatar Christina V. | posted 2 years ago | edited

there do you have any idea how to deal with the "new" iphone pictures extension, .heic ?
I'm using liip_imagine too, follow the parts of the tutorial I needed for my context, but since I'm on a web-app , we have issue with Iphone.

I Google it of course but... Could not find anything link to liip and .heic.


Hey Christina,

But what's the issue exactly? :) Fairly speaking I'm not aware of any problems with it. Can't you upload .heic pictures with LiipImagineBundle? The bundle is just a wrapper around GD / Imagick / Gmagick PHP extensions. You can choose whatever driver you prefer in bundle configuration. Most probably, the latest version of those extensions should support this format I think, but I'm not 100% sure, I just didn't check it. So, I think your plan is to try different drivers and see if some of them support this new format. My advice is to use the latest PHP version for this - it will have more chances to have this support :)

I hope this helps!


Christina V. Avatar
Christina V. Avatar Christina V. | victor | posted 2 years ago | edited

Hola victor .

Thanks for your reply, I appreciate you giving some time

The upload works perfectly. The issue is when I want to render the picture..
I tried different drivers, but it doesn't seems to work.
Anyway, since I could not find a solution, I manage to use Imagick (PHP extension), who allow me to convert a heic file.
I'm still busy with it to be honest, things came in between at work.

If somebody is interested here, I'll be happy to share my class UploadHelper for people.

Have a nice day


Hola Christina!

Hm, if the problem in LiipImagineBundle, probably better to open an issue on their repo, or try to look for a similar issue first, maybe someone already reported this problem.

And thanks for being able to share your solution! I think if anybody is interested - they will ask you about it.



Thank you again for this tutorial!!!

I know that you guys are super busy. But, I was wondering what would the tests folder look like if you did this using TDD. I know it would double the length of this course, and so you would not add it to the script. But there are many unique coding techniques and I would like to see your approach to building the test cases. You could leave them there as bonus material. Tests are a very weak area of my coding as I am usually under pressure to complete. But the apps always grow, and I regret not doing them sooner :(.


Hey Skylar

In theory your test folder should mirror your production folder (src/ directory). When doing TDD you must start with a test first. Usually in that phase is when you take some time to think about architecture, relation between objects, etc, but also it's recomended to code small tests, so you can develop the module or whatever you are doing little by little. TDD requires a lot of practice and a lot of discipline but if every time you code something new, you start from coding some tests, eventually you will get good at it. Probably you will find very interesting this "kata" from Uncle Bob: http://butunclebob.com/Arti...



Wow guys!! This tut is awesome and so filled of knowledge. Thanks again.

Stefan T. Avatar
Stefan T. Avatar Stefan T. | posted 3 years ago

Do You have any final date of release? I'd to subscribe SC like Netflix but 25$ is like 100 in Poland, especially for student 😅


Hey ElGovanni,

Hey, we're working on releasing a new chapter of this course every day. Because it's kinda big course - 33 chapters - it might be fully released in about a month I think, or maybe a bit faster, but not too much. Thank you for your patience! :)

Btw, if you're a student - you're in luck! We provide discounts for students! Please, contact us directly to get more information about it.


Stefan T. Avatar

Oh thanks Victor, I didn't knew about discount for students :)

Christina V. Avatar
Christina V. Avatar Christina V. | posted 3 years ago

Amazing lessons, like usual.
I especially appreciate the way you write (I'm more the kind to read, I never watch videos), that makes me understand things really easily.

Can't wait for the next part!



Thanks Christina V.! We're glad to hear you like our tutorials


Dmitriy Avatar
Dmitriy Avatar Dmitriy | posted 3 years ago

As a wish, is it possible to add breadcrumbs over the course heading? It is difficult to determine which site category the course belongs to.


Hey Dmitriy!

I'm happy to say that we're working on some design changes right now that I *think* will include this - you're not the only person who has asked :).


Genesis Avatar
Genesis Avatar Genesis | posted 3 years ago | edited

I think Flysystem will be interesting part of this course! there WDYT?


It's totally going to be a part of it! :D :D :D + using with LiipImagineBundle + eventually using Flysystem to store everything in S3. FUN stuff :)

2 Reply

Are you going to cover picture resize?


Hey sasa1007!

MAYBE. It depend what you mean - but I'd like to know more :). We WILL cover this case: the user can upload a file of any size, and then when you render them, you resize them to some specific dimensions - e.g. 200x200. What we are *not* currently planning on covering is something like: the user uploads a photo and then there is some JS widget that pops up to allow the user to dynamically resize/crop their photo.

Let me know what you're looking for - and thanks for posting ideas here so early - very helpful!


Gregory B. Avatar
Gregory B. Avatar Gregory B. | weaverryan | posted 3 years ago | edited

weaverryan maybe would it be also great to mention that while LiipImagineBundle is a great tool, some other tools exist outside of the Symfony ecosystem. I'm thinking about Intervention, that comes whith Laravel helpers but could totally be used inside a Symfony application. (Same goes for custom FlySystem adapters). Anyway : thanks for this long awaited series, I have students who will be delighted ;)


Hey Gregory B.!

Awesome tip! Indeed, it looks like if you wanted to programmatically make some changes to an image (like, not just via configuration, but inside a service - run a bunch of methods to transform the image), that is an awesome tool! And combined with Symfony Messenger (so you can async this stuff), that's a pretty killer combo. I will definitely mention it... at the very least :). We will definitely be talking about FlySystem and both the local and S3 adapter (and also a cache adapter).


2 Reply

Hi Ryan!
Now I use vich/uploader-bundle, and problem is when I want to upload image biger thah 5mb he give me error, so I must to download my picture from mobile phone to resize it, and then to upload.

Mixa S. Avatar

Which type of error?
It can be not Symfony-related error but server limitations.

What is the value of upload_max_filesize option in php.ini file (you can check it in SF profiler toolbar)?


I was thinking the same thing :). We'll talk about this. You DO need to bump this setting up, if you want large file uploads. But, if you setup validation correctly, you should at least get a nice validation error (and not some weird 500 error or something like that).


1 Reply

I thought that LiipImagineBundle is for resize picture, so I thought that you will cover that case. Anyway I cant wait to see the rest of videos.

Wish you best!

Mouad E. Avatar
Mouad E. Avatar Mouad E. | posted 3 years ago

this course will be after phpSpec?


Yep! We will start releasing this course next week :)

Cat in space

"Houston: no signs of life"
Start the conversation!