Я пытаюсь загрузить файл, когда пользователь нажимает ссылку на скачивание.
В контроллере:
$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, но я думаю, что это не лучшая практика...
Прежде всего, спасибо всем за ваши ответы. Я, наконец, решил это без 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));
Надеюсь, это поможет!
Наиболее удобным решением является
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
$response = new BinaryFileResponse($file);
$response->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT);
return $response;
Вы не должны использовать 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))
));
X-Sendfile
- это типичный заголовок, который работает как X-Accel-Redirect
. Связанный ответ здесь: stackoverflow.com/questions/80186/…
Не знаю, может ли он помочь, но он application/octet-stream
не application/octect-stream
Как и в 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');
}
+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;
Для тех, у кого нет возможности устанавливать заголовки:
Атрибут download
может помочь в зависимости от того, какие браузеры вам необходимо поддерживать:
<a href="{file url}" download>
или
<a href="{file url}" download="{a different file name}">
Это не поддерживается во всех устаревших браузерах. Смотрите эту страницу для поддержки браузера: