Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PhpSpreadsheet - Download file instead of saving it

I need to generate an excel file (xls) and trigger the download after it is generated. I found this example in the documentation.

<?php

require 'vendor/autoload.php';

use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;

$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->setCellValue('A1', 'Hello World !');

$writer = new Xlsx($spreadsheet);
$writer->save('hello world.xlsx');

It shows how to create a excel file and save it on the server. How can I serve the result to the client instead and "force" him to download it? I need to get the data of the $writer somehow.

I am currently solving it without PhpSpreadsheet:

// Excel Export 
    $filename = 'export_'.date('d-m-y').'.xls';
    $filename = $validator->removeWhitespace($filename);

    header('Content-type: application/ms-excel');
    header('Content-Disposition: attachment; filename='.$filename);
    exit($response["output"]);  // <-- contains excel file content

But it is not working with my delimiter (semicolon). The semicolon is not getting interpreted and everything is getting written into one column.

enter image description here

If I export it as .csv, then it works. But I need it as .xls or .xlsx

like image 373
Black Avatar asked Nov 21 '19 09:11

Black


4 Answers

use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;

class DownloadExcel
{
    public static function createExcel(array $data, array $headers = [],
                                       $fileName = 'data.xlsx')
    {
        $spreadsheet = new Spreadsheet();
        $sheet = $spreadsheet->getActiveSheet();

        for ($i = 0, $l = sizeof($headers); $i < $l; $i++) {
            $sheet->setCellValueByColumnAndRow($i + 1, 1, $headers[$i]);
        }

        for ($i = 0, $l = sizeof($data); $i < $l; $i++) { // row $i
            $j = 0;
            foreach ($data[$i] as $k => $v) { // column $j
                $sheet->setCellValueByColumnAndRow($j + 1, ($i + 1 + 1), $v);
                $j++;
            }
        }

        $writer = new Xlsx($spreadsheet);
        header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
        header('Content-Disposition: attachment; filename="'. urlencode($fileName).'"');
        $writer->save('php://output');
    }

}

This is what I use to create a spreadsheet with PhpSpreadsheet and output directly to php://output for download.

like image 80
Sean Avatar answered Oct 09 '22 21:10

Sean


My answer : PHP:

$writer = new Xlsx($spreadsheet);
ob_start();
$writer->save('php://output');
$ret['data'] = base64_encode(ob_get_contents());
ob_end_clean();

JS:

var linkSource = 'data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,'+ response.data ;
var downloadLink = document.createElement("a");
var fileName = 'clients.' + format;

downloadLink.href = linkSource;
downloadLink.download = fileName;
downloadLink.click();
like image 31
Makooo 111 Avatar answered Oct 09 '22 21:10

Makooo 111


I solved it with a workaround. I temporarily save the file on the server, then I load the content into a variable and serve it as a download file. Then I delete the file from the server.

Workaround:

$date = date('d-m-y-'.substr((string)microtime(), 1, 8));
$date = str_replace(".", "", $date);
$filename = "export_".$date.".xlsx";

try {
    $writer = new Xlsx($response["spreadsheet"]);
    $writer->save($filename);
    $content = file_get_contents($filename);
} catch(Exception $e) {
    exit($e->getMessage());
}

header("Content-Disposition: attachment; filename=".$filename);

unlink($filename);
exit($content);
like image 26
Black Avatar answered Oct 09 '22 20:10

Black


I had the same problem and found a solution here : https://github.com/PHPOffice/PhpSpreadsheet/issues/217

I ended my method with $writer->save('php://output'); then exit()

like image 25
Joachim Avatar answered Oct 09 '22 21:10

Joachim