Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
A small Symfony 2 class for returning a response as a CSV file. Based on the Symfony JsonResponse class.
<?php
namespace Jb\AdminBundle\Http;
use Symfony\Component\HttpFoundation\Response;
class CsvResponse extends Response
{
protected $data;
protected $filename = 'export.csv';
public function __construct($data = array(), $status = 200, $headers = array())
{
parent::__construct('', $status, $headers);
$this->setData($data);
}
public function setData(array $data)
{
$output = fopen('php://temp', 'r+');
foreach ($data as $row) {
fputcsv($output, $row);
}
rewind($output);
$this->data = '';
while ($line = fgets($output)) {
$this->data .= $line;
}
$this->data .= fgets($output);
return $this->update();
}
public function getFilename()
{
return $this->filename;
}
public function setFilename($filename)
{
$this->filename = $filename;
return $this->update();
}
protected function update()
{
$this->headers->set('Content-Disposition', sprintf('attachment; filename="%s"', $this->filename));
if (!$this->headers->has('Content-Type')) {
$this->headers->set('Content-Type', 'text/csv');
}
return $this->setContent($this->data);
}
}
@hvallenilla
Copy link

hvallenilla commented Aug 26, 2015

Excelent feature

@DomWeldon
Copy link

DomWeldon commented Feb 9, 2016

This is great, brilliant little timesaver!

@dunglehome
Copy link

dunglehome commented May 4, 2016

it works like charm, thank you!

@dovy
Copy link

dovy commented Jun 7, 2016

Perfection! Thank you @mathewbyrne.

Using:

$response = new CSVResponse( $data, 200, explode( ', ', $columns ) );
$response->setFilename( "data.csv" );
return $response;

@Alexey-Stogny
Copy link

Alexey-Stogny commented Sep 26, 2016

Nice thing, thanks!
@dovy: not exactly: you seem to provide wrong headers, third param for constructor - it's not about 'table' headers, it's about http response headers!

@Alexey-Stogny
Copy link

Alexey-Stogny commented Sep 26, 2016

still, you can use stream_get_contents instead of multiple fgets to retrieve data from stream

@mcampourcy
Copy link

mcampourcy commented Jan 27, 2017

Nice and very useful, thanks !

@medJemmoudi
Copy link

medJemmoudi commented Jul 11, 2017

works like a charm, thanks a lot!

@degusssa
Copy link

degusssa commented Aug 18, 2017

@mathewbyrne Could you please explain, why do you write to file and then read from it in the same method? I do not understand this approach.

@glauberm
Copy link

glauberm commented Jan 23, 2018

An improved version based on Symfony\Component\Serializer\Encoder\CsvEncoder.

<?php

namespace App\Http;

use Symfony\Component\HttpFoundation\Response;

class CsvResponse extends Response
{
    private $data;
    private $filename;

    public function __construct($filename, $data = array(), $status = 200, $headers = array())
    {
        parent::__construct('', $status, $headers);
        $this->filename = $filename.'_'.md5(uniqid(rand(), true)).'.csv';
        $this->encode($data);
        $this->serve();
    }

    private function encode(array $data)
    {
        $handle = fopen('php://temp', 'w+');

        foreach ($data as $row) {
            fputcsv($output, $row);
        }

        rewind($handle);

        $this->data = stream_get_contents($handle);

        fclose($handle);
    }

    private function serve()
    {
        $this->headers->set('Content-Disposition', sprintf('attachment; filename="%s"', $this->filename));
        if (!$this->headers->has('Content-Type')) {
            $this->headers->set('Content-Type', 'text/csv');
        }

        return $this->setContent($this->data);
    }
}

@thomasbrix
Copy link

thomasbrix commented Dec 1, 2018

Thanks.
@glauberm there's a small misprint in

foreach ($data as $row) { 
    fputcsv($output, $row); 
}

should be

foreach ($data as $row) { 
    fputcsv($handle, $row); 
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment