FileDownloadController.php 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. <?php
  2. namespace Drupal\system;
  3. use Drupal\Core\Controller\ControllerBase;
  4. use Symfony\Component\HttpFoundation\Request;
  5. use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
  6. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  7. use Symfony\Component\HttpFoundation\BinaryFileResponse;
  8. /**
  9. * System file controller.
  10. */
  11. class FileDownloadController extends ControllerBase {
  12. /**
  13. * Handles private file transfers.
  14. *
  15. * Call modules that implement hook_file_download() to find out if a file is
  16. * accessible and what headers it should be transferred with. If one or more
  17. * modules returned headers the download will start with the returned headers.
  18. * If a module returns -1 an AccessDeniedHttpException will be thrown. If the
  19. * file exists but no modules responded an AccessDeniedHttpException will be
  20. * thrown. If the file does not exist a NotFoundHttpException will be thrown.
  21. *
  22. * @see hook_file_download()
  23. *
  24. * @param \Symfony\Component\HttpFoundation\Request $request
  25. * The request object.
  26. * @param string $scheme
  27. * The file scheme, defaults to 'private'.
  28. *
  29. * @return \Symfony\Component\HttpFoundation\BinaryFileResponse
  30. * The transferred file as response.
  31. *
  32. * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
  33. * Thrown when the requested file does not exist.
  34. * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
  35. * Thrown when the user does not have access to the file.
  36. */
  37. public function download(Request $request, $scheme = 'private') {
  38. $target = $request->query->get('file');
  39. // Merge remaining path arguments into relative file path.
  40. $uri = $scheme . '://' . $target;
  41. if (file_stream_wrapper_valid_scheme($scheme) && file_exists($uri)) {
  42. // Let other modules provide headers and controls access to the file.
  43. $headers = $this->moduleHandler()->invokeAll('file_download', [$uri]);
  44. foreach ($headers as $result) {
  45. if ($result == -1) {
  46. throw new AccessDeniedHttpException();
  47. }
  48. }
  49. if (count($headers)) {
  50. // \Drupal\Core\EventSubscriber\FinishResponseSubscriber::onRespond()
  51. // sets response as not cacheable if the Cache-Control header is not
  52. // already modified. We pass in FALSE for non-private schemes for the
  53. // $public parameter to make sure we don't change the headers.
  54. return new BinaryFileResponse($uri, 200, $headers, $scheme !== 'private');
  55. }
  56. throw new AccessDeniedHttpException();
  57. }
  58. throw new NotFoundHttpException();
  59. }
  60. }