Подтвердить что ты не робот

Symfony2 - скачать файл Force

Я пытаюсь загрузить файл, когда пользователь нажимает ссылку на скачивание.

В контроллере:

    $response = new Response();
    $response->headers->set('Content-type', 'application/octect-stream');
    $response->headers->set('Content-Disposition', sprintf('attachment; filename="%s"', $filename));
    $response->headers->set('Content-Length', filesize($filename));

    return $response;

Это открывает диалоговое окно для сохранения файла, но он говорит, что файл имеет 0 байтов. И изменив его на:

        $response = new Response();
        $response->headers->set('Content-type', 'application/octect-stream');
        $response->headers->set('Content-Disposition', sprintf('attachment; filename="%s"', $filename));
        $response->headers->set('Content-Length', filesize($filename));
        $response->headers->set('Content-Transfer-Encoding', 'binary');
        $response->setContent(readfile($filename));

        return $response;

Я получаю кучу странных символов вместо диалогового окна загрузки файла.

Наконец, переключение строки "setContent" на:

    $response->setContent(file_get_contents($filename));

Он возвращает ошибку PHP:

Неустранимая ошибка: допустимый размер памяти...

Любые подсказки о том, как этого достичь? Я сделал это раньше в PHP (с MVC), но я не знаю, чего не хватает, чтобы сделать это через Symfony2...

Возможно, решение задает memory_limit в PHP.INI, но я думаю, что это не лучшая практика...

4b9b3361

Ответ 1

Прежде всего, спасибо всем за ваши ответы. Я наконец решил это без X-SendFile (что, вероятно, является лучшей практикой). В любом случае, для тех, кто не может заставить работать модуль Apache X-Sendfile (виртуальный хостинг), вот решение:

// Generate response
$response = new Response();

// Set headers
$response->headers->set('Cache-Control', 'private');
$response->headers->set('Content-type', mime_content_type($filename));
$response->headers->set('Content-Disposition', 'attachment; filename="' . basename($filename) . '";');
$response->headers->set('Content-length', filesize($filename));

// Send headers before outputting anything
$response->sendHeaders();

$response->setContent(file_get_contents($filename));

return $response;

Надеюсь, это поможет!

Ответ 2

Наиболее удобным решением является

use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;

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

return $response;

Ответ 3

Вы не должны использовать PHP для загрузки файлов, потому что это задача для сервера Apache или Nginx. Для загрузки файлов лучше всего использовать заголовки X-Accel-Redirect (в случае Nginx)/X-Sendfile (в случае Apache).

Следующий фрагмент действия можно использовать с настроенным Nginx для загрузки файлов из Symfony2:

return new Response('', 200, array('X-Accel-Redirect' => $filename));

UPD1: код для Apache с настроенным файлом mod_xsend:

return new Response('', 200, array(
    'X-Sendfile'          => $filename,
    'Content-type'        => 'application/octet-stream',
    'Content-Disposition' => sprintf('attachment; filename="%s"', $filename))
);

Ответ 4

Не знаю, может ли он помочь, но он application/octet-stream не application/octect-stream

Ответ 5

Начиная с Symfony 3.2 вы можете использовать помощник контроллера file(), который является ярлыком для создания BinaryFileResponse, как упоминалось в предыдущем ответе:

public function fileAction()
{
    // send the file contents and force the browser to download it
    return $this->file('/path/to/some_file.pdf');
}

Ответ 6

+1 для ответа Александра.

Но если вы не можете использовать X-Sendfile, вы должны использовать BinaryFileResponse, добавленный в 2.2: http://symfony.com/doc/current/components/http_foundation/introduction.html#serving-files

В моем проекте результат

$response = new \Symfony\Component\HttpFoundation\BinaryFileResponse($dir .DIRECTORY_SEPARATOR. $zipName);

$d = $response->headers->makeDisposition(
    ResponseHeaderBag::DISPOSITION_ATTACHMENT,
    $zipName
   );

$response->headers->set('Content-Disposition', $d);

return $response;

Ответ 7

Для тех, у кого нет возможности устанавливать заголовки:

Атрибут download может помочь в зависимости от того, какие браузеры вам необходимо поддерживать:

<a href="{file url}" download>

или

<a href="{file url}" download="{a different file name}">

Это не поддерживается во всех устаревших браузерах. Смотрите эту страницу для поддержки браузера:

https://www.w3schools.com/tags/att_a_download.asp