6

I asked the question about downloading of files upon submitting a form.

Now I want to clarify how to do it in the case of controller function. That is, some controller is called and its function is being executed.

In the form submit function file downloading starts upon executing the $form_state->setResponse($response);

How to start it in the controller function ?

I tried to use $response->send(); but it sends a file with wrong data and another size.

7

Never send the response with $response->send(). Instead return the response:

use Symfony\Component\HttpFoundation\Response;

public function myController() {
    $response = new Response();
    // prepare $response
    return $response;
  }

BTW, this is a standard Symfony Controller. The fact that you also can return the main content in a render array is because Drupal has added an event subscriber, which converts the main content to a response with the themed html page.


This works for all responses, in your case for example for a binary file response:

Drupal\system\FileDownloadController::download():

  public function download(Request $request, $scheme = 'private') {
    $target = $request->query->get('file');
    // Merge remaining path arguments into relative file path.
    $uri = $scheme . '://' . $target;

    if (file_stream_wrapper_valid_scheme($scheme) && file_exists($uri)) {
      // Let other modules provide headers and controls access to the file.
      $headers = $this->moduleHandler()->invokeAll('file_download', [$uri]);

      foreach ($headers as $result) {
        if ($result == -1) {
          throw new AccessDeniedHttpException();
        }
      }

      if (count($headers)) {
        // \Drupal\Core\EventSubscriber\FinishResponseSubscriber::onRespond()
        // sets response as not cacheable if the Cache-Control header is not
        // already modified. We pass in FALSE for non-private schemes for the
        // $public parameter to make sure we don't change the headers.
        return new BinaryFileResponse($uri, 200, $headers, $scheme !== 'private');
      }

      throw new AccessDeniedHttpException();
    }

    throw new NotFoundHttpException();
  }
| improve this answer | |
  • 1
    Would want BinaryFileResponse though? – Kevin Sep 8 '17 at 6:51
  • 1
    @Kevin, yes, you can return any kind of response. I've added this as example. – 4k4 Sep 8 '17 at 6:57
  • 2
    Are cache headers added to that automatically? – Brian Aug 8 '18 at 18:28
4

My way in Drupal 8 controller;

use Symfony\Component\HttpFoundation\BinaryFileResponse;

$uri = 'public://' . $fileName;

$headers = array(
        'Content-Type'     => 'application/pdf',
        'Content-Disposition' => 'attachment;filename="'.$fileName.'"');

return new BinaryFileResponse($uri, 200, $headers, true);
| improve this answer | |
  • 3
    Welcome to Drupal Answers! We always intend to provide good quality answers that will help the original questioner as well as others that might find this question/answer when searching with similar issues. Your answer does not quite meet these requirements. If you find that your answer adds to the already existing answer, please re-edit, providing more context and a better code snippet that highlights where to apply the statements. Also have a check of the Drupal Coding Standards (drupal.org/docs/develop/standards/coding-standards) and use proper indendation in your code snippets. – Mario Steinitz Mar 4 '19 at 2:03
  • 2
    I appreciate the succinct nature of this answer. – ummdorian Oct 31 '19 at 3:01
  • 1
    Great answer, what I have been looking for, for hours! – Jaeger Jul 1 at 13:33

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.