Download a file in a controller in Magento 2

Controller, Magento 2, Quick Tip

Today i had to create a file download from a Magento 2 controller. I turnes out that this is quite simple. Now, it's good to know that there are 2 options here:

  • You have the file contents available. This is the case when you created an CSV with data for example.

  • The file you want to offer to download is already somewhere on disk. This can be something the user uploaded before.

MageDispatch.com (ad)

Mage Dispatch is a newsletter for the community and by the community. Here you can share links that you think that the community should know about. We will include it in our next newsletter.

Dynamic file contents

First, we need the \Magento\Framework\App\Response\Http\FileFactoryclass:

use Magento\Framework\App\Response\Http\FileFactory;

public function __construct(
    Action\Context $context,
    FileFactory $fileFactory
) {
    parent::__construct($context);
    $this->fileFactory = $fileFactory;
}

Then in our execute method we return the result of the create method:

public function execute()
{
    $contents = $this->orderExport->generateCsv();

    return $this->fileFactory->create('order-export.csv', $contents);
}

And that's it, when you visit this endpoint you will get a file download called order-export.csv.

Existing file

Now this requires an extra dependency as we need to get the path to our file:

use Magento\Framework\Filesystem\DirectoryList;
use Magento\Framework\App\Response\Http\FileFactory;

public function __construct(
    Action\Context $context,
    FileFactory $fileFactory,
    DirectoryList $directory
) {
    parent::__construct($context);
    $this->fileFactory = $fileFactory;
    $this->directory = $directory;
}

Next we calculate the full path and instead of a string with contents, pass an array as contents:

public function execute()
{
    $path = $this->directory->getPath(\Magento\Framework\App\Filesystem\DirectoryList::PUB) . '/uploads/' . $this->getFilename();

    return $this->fileFactory->create($model->getValue(), [
        'type' => 'filename',
        'value' => $path,
    ]);
}

In this case the file must be present in the pub/uploads folder. You can check this file for all folders available by default in Magento.

Remove the file after download

Do you need to remove the file when the download is done? Magento has got your back, just add the rm key:

return $this->fileFactory->create($model->getValue(), [
    'type' => 'filename',
    'value' => $path,
    'rm' => true,
]);

Now your file is deleted after the download is complete.

Want to respond?