web-dev-qa-db-fra.com

Symfony2 - Force le téléchargement de fichier

J'essaie de télécharger un fichier lorsqu'un utilisateur clique sur le lien de téléchargement.

Dans le contrôleur:

    $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;

Ceci ouvre la boîte de dialogue pour enregistrer le fichier, mais indique que le fichier a une taille de 0 octet. Et le changer pour:

        $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;

Je reçois un tas de caractères étranges au lieu de la boîte de dialogue de téléchargement de fichier.

Enfin, basculez la ligne "setContent" sur:

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

Il retourne une erreur PHP:

Erreur fatale: taille de mémoire autorisée ...

Des indices sur comment y parvenir? Je l'ai déjà fait auparavant dans PHP (sans MVC), mais je ne sais pas ce qui peut manquer pour le faire via Symfony2 ...

Peut-être que la solution consiste à définir memory_limit dans PHP.INI, mais je suppose que ce n’est pas la meilleure pratique ...

52
Xavi

Tout d’abord, merci à tous pour vos réponses. J'ai finalement résolu ceci sans X-SendFile (ce qui est probablement la meilleure pratique). Quoi qu'il en soit, pour ceux qui ne peuvent pas utiliser le module Apache X-Sendfile (hébergement partagé), voici une solution:

// 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;

J'espère que cela t'aides!

49
Xavi

La solution la plus confortable est

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

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

return $response;
84
denkweite

Vous ne devez pas utiliser PHP pour télécharger des fichiers car il s’agit d’une tâche destinée à un serveur Apache ou Nginx. La meilleure option est d’utiliser X-Accel-Redirect (dans le cas de Nginx)/X-Sendfile ( dans le cas d’Apache) en-têtes pour le téléchargement de fichiers.

L'extrait d'action suivant peut être utilisé avec Nginx configuré pour télécharger des fichiers à partir de Symfony2:

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

PD1: Code pour Apache avec mod_xsendfile configuré:

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

Je ne sais pas si ça peut aider mais c'est application/octet-stream ne pas application/octect-stream

8
Pascal

Depuis Symfony 3.2, vous pouvez utiliser l’assistant du contrôleur file () , qui est un raccourci pour créer un BinaryFileResponse comme mentionné dans une réponse précédente:

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

+1 pour la réponse d'Alexandre.

Mais si vous ne pouvez pas utiliser X-Sendfile, vous devez utiliser le BinaryFileResponse ajouté dans la version 2.2: http://symfony.com/doc/current/components/http_foundation/introduction.html#serving-files =

Dans mon projet, le résultat est

$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;
6
Jaycreation

Pour ceux qui n'ont pas la possibilité de définir des en-têtes:

L'attribut download peut être utile selon les navigateurs à prendre en charge:

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

ou

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

Ceci n'est pas supporté par tous les navigateurs existants. Voir cette page pour le support du navigateur:

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

2
Henry