Je crée un contrôleur "Télécharger" à l'aide de Symfony 2, qui a pour seul but d'envoyer des en-têtes afin que je puisse forcer le téléchargement d'un fichier .csv, mais cela ne fonctionne pas correctement.
$response = new Response();
$response->headers->set('Content-Type', "text/csv");
$response->headers->set('Content-Disposition', 'attachment; filename="'.$fileName.'"');
$response->headers->set('Pragma', "no-cache");
$response->headers->set('Expires', "0");
$response->headers->set('Content-Transfer-Encoding', "binary");
$response->headers->set('Content-Length', filesize($fileName));
$response->prepare();
$response->sendHeaders();
$response->setContent(readfile($fileName));
$response->sendContent();
$fileName
est une chaîne "info.csv"
. Telles sont mes actions à l'intérieur de mon contrôleur, il n'y a pas de déclaration de retour. Lorsque j'ai essayé de renvoyer l'objet Response
, le contenu du fichier était affiché dans le navigateur, pas le résultat escompté.
Le problème que j'ai constaté est que dans certaines pages, je reçois mon info.csv file
, mais dans les autres, tout ce que je reçois est un message:
No webpage was found for the web address: http://mywebpage.com/download
Error 6 (net::ERR_FILE_NOT_FOUND): The file or directory could not be found.
Je suis tout à fait sûr que le fichier existe, alors il doit y avoir une autre chose qui ne va pas. En outre, routing.yml fonctionne correctement, car j’obtiens le fichier d’autres pages qui renvoient également à ce chemin .. .. Le journal des erreurs Apache n’affiche rien à ce sujet.
Quelqu'un a-t-il déjà forcé le téléchargement d'un fichier .csv sur Symfony 2? Si oui, qu'est-ce que je fais mal?
Voici un exemple minimal qui fonctionne très bien en production:
class MyController
public function myAction()
$response = $this->render('ZaysoAreaBundle:Admin:Team/list.csv.php',$tplData);
$response->headers->set('Content-Type', 'text/csv');
$response->headers->set('Content-Disposition', 'attachment; filename="teams.csv"');
return $response;
Vous pouvez remplacer l'appel de rendu par new response et response-> setContent si vous le souhaitez.
Votre commentaire sur l'absence de déclaration de retour dans un contrôleur est déconcertant. Les contrôleurs renvoient une réponse. Laissez le cadre s’occuper d’envoyer les éléments au navigateur.
Je me rends compte que ce post est un peu vieux et qu’il n’ya curieusement aucune ressource sur la façon de faire un export CSV dans symfony 2 en plus de ce post sur stackoverflow.
Quoi qu'il en soit, j'ai utilisé l'exemple ci-dessus pour un site de concours client et cela a très bien fonctionné. Mais aujourd’hui, j’ai reçu un e-mail et après l’avoir testé moi-même, le code s’est cassé - le téléchargement a fonctionné avec une petite quantité de résultats, mais la base de données exportant maintenant plus de 31 000 lignes, elle a simplement montré le texte ou avec chrome, fondamentalement n'a rien fait.
Pour tous ceux qui ont un problème avec une exportation de données volumineuse, voici ce que j'ai réussi à faire pour me rendre au travail, en faisant essentiellement ce que Cerad a suggéré comme solution alternative:
$filename = "export_".date("Y_m_d_His").".csv";
$response = $this->render('AppDefaultBundle:Default:csvfile.html.twig', array('data' => $data));
$response->setStatusCode(200);
$response->headers->set('Content-Type', 'text/csv');
$response->headers->set('Content-Description', 'Submissions Export');
$response->headers->set('Content-Disposition', 'attachment; filename='.$filename);
$response->headers->set('Content-Transfer-Encoding', 'binary');
$response->headers->set('Pragma', 'no-cache');
$response->headers->set('Expires', '0');
$response->prepare();
$response->sendHeaders();
$response->sendContent();
ÉDITER: Après plus de tests et d’augmentation du nombre maximal de secondes autorisé, j’ai réalisé que le code précédent imprimait les en-têtes en haut; j’ai donc mis à jour le code.
Cela a fonctionné pour moi pour exporter CSV et JSON.
Les fichiers de brindille sont nommés: export.csv.twig, export.json.twig
Le controlle :
class PrototypeController extends Controller {
public function exportAction(Request $request) {
$data = array("data" => "test");
$format = $request->getRequestFormat();
if ($format == "csv") {
$response = $this->render('PrototypeBundle:Prototype:export.' . $format . '.twig', array('data' => $data));
$filename = "export_".date("Y_m_d_His").".csv";
$response->headers->set('Content-Type', 'text/csv');
$response->headers->set('Content-Disposition', 'attachment; filename='.$filename);
return $response;
} else if ($format == "json") {
return new Response(json_encode($data));
}
}
}
Le routage:
prototype_export:
pattern: /export/{_format}
defaults: { _controller: PrototypeBundle:Prototype:export, _format: json }
requirements:
_format: csv|json
Les brindilles:
export.csv.twig (faites votre chose séparée par une virgule ici, ceci est juste un test)
{% for row in data %}
{{ row }}
{% endfor %}
export.json.twig (les données sont envoyées json_encoded, ce fichier est vide)
J'espère que cela t'aides!
fonction simple que vous pouvez utiliser dans tous les cas pour exporter un csv à télécharger ...
public function getResponse(array $data, $filename, $headers = array())
{
if(substr(strtolower($filename), -4) == '.csv') {
$filename = substr($filename, 0, -4);
}
$tmpFile = $this
->_getContainer()
->get('kernel')
->getRootDir()
. '/../var/tmp_'.substr(md5(time()),0,5);
if(file_exists($tmpFile)) unlink($tmpFile);
$handle = fopen($tmpFile, 'w');
foreach ($data as $i => $row) {
$row = (array) $row;
if($i == 0) fputcsv($handle, array_keys($row));
fputcsv($handle, $row);
}
fclose($handle);
$Response = new Response(file_get_contents($tmpFile));
unlink($tmpFile);
$filename = preg_replace('[^a-z0-9A-Z_]', '', $filename);
$headers = array_merge([
'Expires' => 'Tue, 01 Jul 1970 06:00:00 GMT',
'Cache-Control' => 'max-age=0, no-cache, must-revalidate, proxy-revalidate',
'Content-Disposition' => 'attachment; filename='.$filename.'.csv',
'Content-Type' => 'text/csv',
'Content-Transfer-Encoding' => 'binary',
], $headers);
foreach ($headers as $key => $val) {
$Response->headers->set($key, $val);
}
return $Response;
}
Voici comment j'ai réussi à faire en sorte que Silex retourne un csv:
// $headers in an array of strings
// $results are the records returned by a PDO query
$stream = function() use ($headers, $results) {
$output = fopen('php://output', 'w');
fputcsv($output, $headers);
foreach ($results as $rec)
{
fputcsv($output, $rec);
}
fclose($output);
};
return $app->stream($stream, 200, array(
'Content-Type' => 'text/csv',
'Content-Description' => 'File Transfer',
'Content-Disposition' => 'attachment; filename="test.csv"',
'Expires' => '0',
'Cache-Control' => 'must-revalidate',
'Pragma' => 'public',
));
Vous devrez peut-être aussi faire un peu de Jiggery Pokery avec Javascript (je téléchargeais via AJAX) mais ceci post était tout ce dont j'avais besoin pour que cela fonctionne.