Search code examples
symfonydownloadsymfony5

Symfony: Export (CSV) File has limit?


I'm trying to send a generated CSV file using Symfony 5 and somehow seem to have reached a limit I can't overcome. For testing reasons I have broken it down to the basic of the basics; so I send static data, generate a txt-file and do no logic whatsoever. In my example code below, if I do 65 iterations the file is generated and sent to the browser as a download (that's 4KB). If I do 66 or add a single letter to the $data sample data string it's all displayed in the browser window. The exact same code works perfectly well outside Symfony even with 1000 iterations. I also don't get an error or anything out of the dev.log that could help.

public function saveCSV(Request $request, DelcampeParser $parser) {
    $response = new Response();

// same with
//  $response = new StreamedResponse();
//  $response->setCallback(function(){});

    $response->headers->set('Content-Type', 'text/plain; charset=utf-8');
    $disposition = HeaderUtils::makeDisposition(
        HeaderUtils::DISPOSITION_ATTACHMENT,
        'foo.txt'
    );
    $response->headers->set('Content-Disposition', $disposition);

    $data = array(0 => 'abcdefghijklmnopqrstuvwxyz');
    for ($a=1;$a<=66;$a++) {
        var_dump($data);
    }

    return $response;
}

What's wrong? Why am I not able to generate a bigger file in Symfony?

Thank you.

[edit] I have a new theory: PHP's output buffering is set to 4KB. Whenever the buffer is full, buffered data is sent to the Browser. That unfortunately happens before the headers have been sent by Symfony, thus generating a browser output. How can I change that behavior?


Solution

  • I now have an answer with StreamedResponse that works and hopefully also fulfills all requirements and recommendations by Symfony:

    // in the Controller
    public function saveCSV(Request $request, Parser $parser) {
        $response = new StreamedResponse();
    
        $data = $request->get("sd");    // sd comes out of a form that posts a multidimensional array
        $response->setCallback(function() use ($data, $parser) {
            $parser->generateCSV($data);
        });
    
        $response->headers->set('Content-Type', 'text/csv; charset=utf-8');
        $disposition = HeaderUtils::makeDisposition(
            HeaderUtils::DISPOSITION_ATTACHMENT,
            "delcampeimport_".date("Ymd-Hi").".csv",
        );
        $response->headers->set('Content-Disposition', $disposition);
    
        return $response;
    }
    

    and my Service

    public function generateCSV($dataarray) {
        $out = fopen('php://output', 'w+');
    
        // send header rows of csv file
        fputs($out, "website_visibility,category_id,title, /* ..., */ images\r\n");
    
        // generate data
        foreach($dataarray AS $stamp) {
            $stampdata = array ( 
                'a' => 'CH',
                'b' => $stamp['category'],
                'c' => htmlentities($stamp['title']),
                // ...
                'aa' => $stamp['img1'].
                ($stamp['img2'] ? ";".$stamp['img2']:"").
                ($stamp['img3'] ? ";".$stamp['img3']:"")
            );
    
            // send csv data
            fputcsv($out, $stampdata);
        }
        fclose($out);
    }
    

    Thanks for the inputs