Skip to content
FULLTime eCommerce

Protecting uploaded files – private storage & signed links

Note: Available from version 2.5.0

Up to version 2.4.x, uploaded customer files lived under public/uploads/ and were served directly by the web server – without any check. Anyone who knew the path could retrieve the file. And that path appears in the customer's order confirmation, in the internal notification email and in the administration.

For print artwork that is usually harmless. As soon as your customers upload ID copies, medical certificates, prescriptions or engineering drawings, it no longer is.

From 2.5.0 you can have those files stored outside the public directory. They are then served only through a signed link that carries its own authorisation and expires after a period you define.

The three settings

You will find them in the plugin settings under File downloads.

SettingDefaultEffect
Store uploads privately and use signed download linkson update: off, on fresh install: onDetermines where new uploads are stored
Download link lifetime in days90How long a link in an already sent email keeps working. 0 = unlimited
Keep serving legacy public pathsonKeeps links working that were sent before the changeover

Why the lifetime rarely gets in the way

The lifetime applies only to links in emails that have already been sent. In the customer account, on the order completion page and in the administration the link is regenerated on every request and is therefore always valid.

So only two cases are affected: guest customers digging out an old order confirmation, and staff opening an archived internal email – and the latter can also find the file in the administration.

90 days cover the 14-day right of withdrawal plus the usual complaint period with room to spare. If you work with long-running processes – custom manufacturing, construction drawings – raise the lifetime or set it to 0.

The changeover step by step

Every step can be undone individually.

1. Install the update

Nothing changes at first. On an update, private storage stays switched off so that your existing email templates keep working unchanged.

2. Switch over the email templates

In your templates, replace the hand-built path with the link the plugin supplies:

Before

<a href="{{ url('frontend.home.page') }}uploads/final/{{ upload.qquuid }}/{{ upload.fileName }}">{{ upload.fileName }}</a>

After

<a href="{{ upload.downloadUrl }}">{{ upload.fileName }}</a>

This works immediately and does not change the behaviour yet: as long as private storage is off, downloadUrl returns exactly the public path your template used to build itself.

Both templates are affected: the order confirmation to the customer and the internal email to your team.

Why this is the most important step: with downloadUrl, your templates never assemble the path themselves again. Future changes to the storage location stay invisible to you – exactly the problem this changeover is causing right now will not happen a second time.

3. Switch on private storage

From now on, new uploads land outside the public directory and are served only through signed links. Existing files stay where they are and remain reachable.

4. Move existing files

bin/console futi:uploads:migrate --dry-run

The dry run shows how many files are affected and how much storage they occupy, without changing anything. If you are happy with it:

bin/console futi:uploads:migrate

The command works in batches, skips files that have already been moved, and can be aborted and restarted at any time.

As long as files remain in the public directory, a notice in the plugin settings points this out.

The setting only controls where new uploads are stored. Delivery always follows the actual storage location of each individual file:

  • File is stored privately → signed link, regardless of the setting
  • File is stored publicly → public path

That is why you can switch the setting on and off again without a single link pointing nowhere – not even after a migration.

Prerequisite

Private storage uses Shopware's private filesystem. In the default configuration that is a local directory (files/) outside the document root – nothing to do there.

If you have switched the private filesystem to remote storage (S3 or similar), please leave the setting switched off.

Customers do not see an error page but a notice pointing them to the order overview in their customer account. From there the file is reachable at any time, because the link is regenerated on every request.

Was this page helpful?

Support

Rented Plugins (Shopware Store)

For support with plugins rented from the Shopware Store, please open a support ticket in your Shopware account.

Create Shopware Ticket

General Inquiries

For general questions or purchase licenses, reach us by email.

Send Email
Protecting uploaded files – private storage & signed links | FULLTime eCommerce