Comment forcer le téléchargement A. fichier csv dans Symfony 2, en utilisant L'objet Response?
je fais un contrôleur" Download " en utilisant Symfony 2, qui a pour seul but d'envoyer des en-têtes pour que je puisse forcer un .fichier csv télécharger, mais il 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 un "info.csv"
chaîne de caractères. Ce sont mes actions à l'intérieur de mon contrôleur, il n'y a pas de déclaration de retour. Quand j'ai essayé de retourner les Response
objet, le contenu du fichier a été affiché dans le navigateur, pas mon résultat prévu.
le problème que j'ai trouvé est que dans certaines pages je obtenez ma info.csv file
, mais dans d'autres tout ce que je reçois 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 absolument sûr que le fichier existe, donc il doit y avoir une autre chose qui ne va pas. Aussi, de routage.yml fonctionne correctement, puisque j'obtiens le fichier à partir d'autres pages qui pointent aussi vers ce chemin. Le journal des erreurs Apache ne montre rien à ce sujet.
quelqu'un A forcé le téléchargement d'un .fichier csv sur Symfony 2 avant? Si oui, ce que je fais mal?
6 réponses
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 une nouvelle réponse et une réponse - > setContent si vous voulez.
Votre commentaire sur aucune instruction de retour à l'intérieur d'un contrôleur est déroutante. Les contrôleurs renvoient une réponse. Laissez le framework s'occuper de l'envoi de la substance au navigateur.
je me rends compte que ce post est un peu vieux et qu'il n'y a, étrangement assez, pratiquement pas de bonnes ressources sur la façon de faire une exportation CSV dans symfony 2 à part ce post à stackoverflow.
de toute façon, j'ai utilisé l'exemple ci-dessus pour un site de concours de client et il a fonctionné assez bien. Mais aujourd'hui j'ai reçu un e-mail et après l'avoir testé moi - même, le code avait cassé-j'ai pu obtenir le téléchargement en travaillant avec une petite quantité de résultats, mais la base de données exportant maintenant plus de 31.000 lignes il soit simplement montré le texte ou avec chrome, simplement fait rien.
pour toute personne ayant un problème avec une exportation de données importante, c'est ce que j'ai demandé pour se mettre au travail, essentiellement faire ce que Cerad a suggéré comme une autre façon:
$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();
EDIT: après plus de tests et d'augmenter le nombre maximum de secondes autorisées, j'ai réalisé que le code précédent imprimait les en-têtes en haut, donc j'ai mis à jour le code.
cela a fonctionné pour moi pour exporter CSV et JSON.
les fichiers de brindilles sont nommés : export.csv.brindille, à l'exportation.json.brindille
Le Contrôleur :
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:
exporter.csv.brindille (faites de votre séparation par virgule chose ici, c'est juste un test)
{% for row in data %}
{{ row }}
{% endfor %}
exporter.json.rameau (les données sont envoyées json_encoded, ce fichier est vide)
Espérons que cette aide!
Voici comment J'ai réussi à obtenir de Silex de retourner 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 pourriez aussi avoir besoin de 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 ça marche.
fonction simple que vous pouvez utiliser pour chaque cas pour exporter un csv pour le téléchargement...
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;
}
Que Diriez-vous d'utiliser L'exportateur de Sonata:
use Exporter\Writer\CsvWriter;
/**
* @param array $orders
*/
public function exportToCsv($orders)
{
$rootdir = $this->get('kernel')->getRootDir();
$filename = $rootdir . '/data/orders.csv';
unlink($filename);
$csvExport = new CsvWriter($filename);
$csvExport->open();
foreach ($orders as $order)
{
$csvExport->write($order);
}
$csvExport->close();
return;
}
Il se bloque si le fichier existe déjà, donc les dissocier-commande.