rrubiorr81
rrubiorr81

Reputation: 305

symfony downloading video from url

I’m trying to download a video from an extrernal URL using symfony. So i have this route, if i click on it directly in the browser, I receive two possible answers: the video is played or (if the browser is unable to reproduce it), the video is downloaded from this external URL. What i’m trying to create is a response from the Controller to always download the video. I’ve tried several solution with no luck.

Some tried solutions:

$response = new BinaryFileResponse($url);
$response->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT);

return $response;

Since it’s not a static file is failing.

Also tried

$response = new RedirectResponse($url);
$response->headers->set('Content-Type', 'video');
$d = $response->headers->makeDisposition(
ResponseHeaderBag::DISPOSITION_ATTACHMENT,
$videoUrl
);
$response->headers->set('Content-Disposition', $d);

And of course the ‘StreamedResponse’… I'm assuming this is possible since i'm getting the desired behavior when the format is not properly traduced in the browser... Any help is appreciated.

Upvotes: 2

Views: 4057

Answers (1)

Shira
Shira

Reputation: 6560

I don't think BinaryFileResponse works with URLs. You should be getting an exception about the file not being readable.


Take a look at StreamedResponse. You can use a custom callback to stream any data to the browser:

use Symfony\Component\HttpFoundation\StreamedResponse;

// ...

$response = new StreamedResponse();

// attempt to generate a filename from the URL's path
$filename = @preg_replace('~[^\w\-.]+~', '', iconv('UTF-8', 'ASCII//TRANSLIT', pathinfo(urldecode(parse_url($url, PHP_URL_PATH)), PATHINFO_BASENAME))) ?: 'video';

// set headers to force file download
$response->headers->set('Content-Type', 'application/force-download');
$response->headers->set(
    'Content-Disposition',
    $response->headers->makeDisposition(
        ResponseHeaderBag::DISPOSITION_ATTACHMENT,
        $filename
    )
);

// stream content from the URL to the browser
$response->setCallback(function () use ($url) {
    $c = curl_init($url);
    curl_exec($c);
    curl_close($c);
});
  • if $url comes from the user you need to validate it (if you don't then users can abuse it)
  • the remote file will be downloaded and streamed through your app so you might run into problems with large files/slow connections/timeouts
  • there is no way to force download of a remote resource without streaming it yourself (unless the remote server explicitly supports it), hence the cURL solution

Regarding your other attempt:

  1. video isn't a valid Content-Type
  2. the second argument of makeDisposition() should be a ASCII file name, not an URL
  3. it doesn't make sense to set such headers for RedirectResponse - it just redirects the browser so the Content-Disposition will not apply to the destination URL

Upvotes: 6

Related Questions