2

The function file_entity_download_uri() seems to no longer exist in Drupal 8.4, and I need to build a download URL for a file. I would not like to directly expose the file location.

  • 1
    If you used Media, I built a module for this purpose: drupal.org/project/media_entity_download - it will take file(s) in a media object and give them an instant download uri. If you just have a file field, you're basically looking at what private files option does. There is also something called file field pretty paths or something like that, but I am not 100% on what it does. In the end, you'd need a solution that ensures a BinaryFileResponse from a controller, you can see an example in my module. – Kevin Jan 12 '18 at 13:49
  • Yes, that would solve my problem. – José Trindade Jan 12 '18 at 15:25
2

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.

1

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);

  • 1
    Original question stated they did not want to give away the physical file url. – Kevin Jan 12 '18 at 14:44
0

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;

  }

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.