Drupal - How do I create a file download URL?

If you used a Media field, I built a module for this purpose: http://drupal.org/project/media_entity_download - it will take file(s) in a media object and give them an instant download uri. It will not show the actual file path to the user.

If you just have a file field, you're basically looking at what private files option does.

In the end, you'd need a solution that ensures a BinaryFileResponse from a controller, you can see an example in my module.


If you just have a static file(s) on your server that you want users to download, such as in the /files dir (suggest using /files/downloads/[filename]). You will want to create a route and controller for this. Then render the link via the route in a block. You could also have a form whos submit handler calls the route with required filename.

This should also not show the actual filepath to the user, just the filename and that its from your site http://example.com

Also note: I added this here due to the title of the OP issue... Might save someone some time in the future when googling 'Drupal 8 file download link'.

example.routing.yml

example.download.file:
  path: '/download/file/{file_name}'
  defaults:
    _controller: '\Drupal\example\Controller\Download::downloadFile'
  requirements:
    _permission: 'access content'

src/Controller/Download.php

<?php

namespace Drupal\example\Controller;

use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpFoundation\BinaryFileResponse;

/**
 * Handle /download/file/ URLs to redirect to content download based on filename.
 */
class Download extends ControllerBase {

  /**
   * Download file.
   *
   * @param string $filename
   *   The filename.
   */
  public function downloadItemTypeExport($filename) {

    // Do some file validation here, like checking for extension.

    // File lives in /files/downloads.
    $uri_prefix = 'public://downloads/';

    $uri = $uri_prefix . $filename;

    $headers = [
      'Content-Type' => 'text/csv', // Would want a condition to check for extension and set Content-Type dynamically
      'Content-Description' => 'File Download',
      'Content-Disposition' => 'attachment; filename=' . $filename
    ];

    // Return and trigger file donwload.
    return new BinaryFileResponse($uri, 200, $headers, true );

  }
}

src\Plugin\Block code

<?php

namespace Drupal\example\Plugin\Block;

use Drupal\Core\Block\BlockBase;
use Drupal\Core\Url;

/**
 * @Block(
 *   id = "example_download_files",
 *   admin_label = @Translation("Example Download Files"),
 *   category = @Translation("Example")
 * )
 */
class ExampleDownloadFiles extends BlockBase {

  /**
   * {@inheritdoc}
   */
  public function build() {
    $build = [];


    $items = [
      'Foo' => 'foo.csv',
      'Bar' => 'bar.csv',
      'Herp' => 'herp.csv',
      'Derp' => 'derp.csv'
    ];


    foreach ($items as $item => $filename) {
      $url = Url::fromRoute('example.download.file', ['file_name' => $filename]);
      $links[$item] = [
        '#title' => $this->t($item),
        '#type' => 'link',
        '#url' => $url
      ];
    }

    $file_download_list = [
      '#theme' => 'item_list',
      '#items' => $links
    ];

    $build['file_downloads'] = [
      '#type' => 'container',
      'file_downloads_prefix' => ['#type' => 'html_tag', '#tag' => 'p', '#value' => $this->t('Download the csv:')],
      'file_downloads_list' => $file_download_list,

    ];

    return $build;

  }

if you are using media this code might work for you :

$file = Media::load(your_file_id); $file_uri = $file->field_file->entity->getFileUri(); $file_downloadable_link = file_create_url($file_uri);

Tags:

Files

8