2012-04-24 9 views
16

Realizzo un controller "Download" utilizzando Symfony 2, che ha l'unico scopo di inviare intestazioni in modo da poter forzare il download di un file .csv, ma non funziona correttamente.Come forzare il download di un file .csv in Symfony 2, usando l'oggetto Response?

$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 è una stringa "info.csv". Queste sono le mie azioni all'interno del mio controller, non ci sono dichiarazioni di ritorno. Quando ho provato a restituire l'oggetto Response, i contenuti del file sono stati visualizzati nel browser, non il risultato previsto.

Il problema che ho trovato è che in alcune pagine faccio ad avere il mio info.csv file, ma in anothers tutto quello che ottiene è un messaggio:

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.

Sono completamente sicuro che il file esiste , quindi ci deve essere un'altra cosa sbagliata. Inoltre, routing.yml funziona correttamente, dal momento che ottengo il file da altre pagine che si collegano anche a quel percorso. Il log degli errori di Apache non mostra nulla a riguardo.

Qualcuno ha forzato il download di un file .csv su Symfony 2 in precedenza? In tal caso, cosa sto sbagliando?

risposta

33

Ecco un esempio minimo che funziona bene nella produzione:

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; 

È possibile sostituire la chiamata rendering con risposta nuova e response-> setContent, se volete.

Il tuo commento sulla dichiarazione di non ritorno all'interno di un controller è sconcertante. I controllori restituiscono una risposta. Lascia che il framework si occupi di inviare le cose al browser.

+0

$ tpldata è undefined –

7

Mi rendo conto che questo post è un po 'vecchio e che non c'è, stranamente, praticamente nessuna buona risorsa su come fare un'esportazione CSV in symfony 2 oltre a questo post su StackOverflow.

In ogni caso, ho utilizzato l'esempio precedente per un sito di contest per clienti e ha funzionato abbastanza bene. Ma oggi ho ricevuto una e-mail e dopo averlo provato personalmente, il codice si è rotto: sono riuscito a ottenere il download con una piccola quantità di risultati, ma il database ora esportava oltre 31.000 righe o mostrava semplicemente il testo o Chrome, fondamentalmente non ha fatto nulla.

Per chiunque abbia problema con un grande esportazione dei dati, questo è quello che manged per andare al lavoro, in pratica a fare quello CERAD suggerito come un modo alternativo:

$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: Dopo altre prove e aumentando al massimo secondi consentiti, ho capito che il codice precedente stava stampando le intestazioni nella parte superiore, quindi ho aggiornato il codice.

+1

Grazie per questo. Ho dovuto passare l'oggetto Request Request $ tramite il metodo $ response-> prepare() per farlo funzionare. – Acyra

5

Questo ha funzionato per esportare CSV e JSON.

I file di Twig sono denominati: export.csv.twig, export.json.ramoscello

Il controllore:

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)); 
    } 
} 
} 

Il Routing:

prototype_export: 
    pattern: /export/{_format} 
    defaults: { _controller: PrototypeBundle:Prototype:export, _format: json } 
    requirements: 
     _format: csv|json 

i ramoscelli:

export.csv.twig (fare la tua virgola cosa separati qui, questo è solo un test)

{% for row in data %} 
{{ row }} 
{% endfor %} 

export.json.twig (i dati vengono inviati json_encoded, questo file è vuoto)

Spero che questo aiuti!

-1

Come sull'utilizzo esportatore di 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; 

} 

Si blocca se il file esiste già, così l'unlink-comando.

+0

In che modo questo aiuta l'OP a scaricare un CSV attraverso il browser? In ogni caso prova a verificare se il file esiste prima di provare a scollegarlo .... –