Slim Framework & PHPExcel, let Slim download generated excel document


#1

Hi all,

For a application i’m creating with AngularJS and Slim Framework I need the possibility to create excel files and automaticly download it.

To be able to create Excel docs, i’m using PHPExcel. But I can’t figure out how to download the created file directly from my server.

try {
        $objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007');
        $objWriter->save('php://output');
        $this->msg = 'Success!';
        $this->statuscode = 200;
    } catch (Exception $e) {
        $this->msg = "Export failed!";
        $this->statuscode = 500;
    }

This outputs in my browser binary code, but doesn’t download the file. Hope someone can help me.


#2

@svanbelleghem, I’ve never used PHPExcel before, but this has worked for me in the past:

$document = "First, Last\n";
$document .= "Jimmy,Page\n";

header('Content-Type: text/xls');
header('Content-Disposition: attachment; filename="myfile.xls"'); 
echo $document;

#3

Thanks for the reply!

But this has the sme result as previously described, all this does is output the text to my browser. What I need is to download desired file.


#4

Hmmm…When I run that code in my browser it downloads a file titled ‘myfile.xsl’.


#5

Try out this:

header(‘Content-Description: File Transfer’);
header(‘Content-Type: application/octet-stream’);
header(“Pragma: public”);
header(“Expires: 0”);
header(“Cache-Control:must-revalidate, post-check=0, pre-check=0”);
header(“Content-Type: application/force-download”);
header(“Content-Type: application/download”);
header(‘Content-Disposition: attachment; filename=“myfile.xls”’);
header(“Content-Transfer-Encoding: binary”);
//header('Content-Length: ’ . filesize($f)); /* perhaps also provide content length */


#6

Thank you for the response!

Made some changed in my code but still doesn’t download the file.

Headers:

Response:

Code:

   $res = $response->withHeader('Content-Description', 'File Transfer')
                ->withHeader('Content-Type', 'application/force-download')
                ->withHeader('Content-Type', 'application/download')
                ->withHeader('Content-Disposition', 'attachment;filename="'.basename($file).'"')
                ->withHeader('Expires', '0')
                ->withHeader('Cache-Control', 'must-revalidate')
                ->withHeader('Pragma', 'public')
                ->withHeader('Content-Length', filesize($file));

            readfile($file);
            return $res;

#7

I created a page that downloads a .csv file recently.

I have a html file that takes in 2 dates that will do a post using slim. The php code will then create a .csv file and populate it based on the data returned form a mysqli query. I have tested this in chrome, firefox, and safari.

Code;

   $app->post('/api/dateRangeReport',function ($request, $response, $args) {
	$jsonArgs = $request->getParsedBody();
	
	header('Content-type: text/csv');
	$name = $jsonArgs['startDate']." through ".$jsonArgs['endDate'].".csv";
	header('Content-Disposition: attachment; filename="'.$name.'"'); 

	// do not cache the file
	header('Pragma: no-cache');
	header('Expires: 0');

	// create a file pointer connected to the output stream
	$file = fopen('php://output', 'w');

	// send the column headers
	fputcsv($file, array('tracking_number', 'store', 'street', 'state', 'zip', 'city', 'country', 'date', 'serial_number'));
	global $fawkesEngine;
	$results = $fawkesEngine->createDateRangeReport($jsonArgs);
	
	$data = array();
	// need to do some special formatting to prevent scientific notation
	foreach ($results as $value) {
		$formattedTrackingNumber = $value['tracking_number'];
		$formattedTrackingNumber = "=".'"'.$formattedTrackingNumber.'"';
		$formattedSerialNumber = $value['serial_number'];
		$formattedSerialNumber = "=".'"'.$formattedSerialNumber.'"';
		$dataTemp = array($formattedTrackingNumber,$value['store'],$value['street'],$value['state'],$value['zip'],$value['city']
				,$value['country'],$value['received_date'],$formattedSerialNumber);
			array_push($data, $dataTemp);
	}

	// output each row of the data
	foreach ($data as $row)
	{
		fputcsv($file, $row);
	}
	fclose($file);
	exit;
  });

#8

I have the exact same issue. Did you manage to fix it?

Thanks,
JF


#9

Maybe try this example to send a CSV file to the browser as download:

public function downloadCsv(Request $request, Response $response): ResponseInterface
{
	$response = $response->withHeader('Content-Type', 'text/csv');
	$response = $response->withHeader('Content-Disposition', 'attachment; filename="file.csv"');

    $stream = fopen('php://memory', 'r+');
    fwrite($stream, file_get_contents(__DIR__ . '/file.csv'));
    rewind($stream);

    return $response->withBody(new \Slim\Http\Stream($stream));
}

To send a Excel (XLSX) file, you just need a different content-type:

public function downloadExcel(Request $request, Response $response): ResponseInterface
{
    $excel = new PHPExcel();

    $sheet = $excel->setActiveSheetIndex(0);
    $cell = $sheet->getCell('A1');
    $cell->setValue('Test');
    $sheet->setSelectedCells('A1');
    $excel->setActiveSheetIndex(0);

    $excelWriter = PHPExcel_IOFactory::createWriter($excel, 'Excel2007');

    $excelFileName = __DIR__ . '/file.xlsx';
    $excelWriter->save($excelFileName);

    // For Excel2007 and above .xlsx files   
    $response = $response->withHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
	$response = $response->withHeader('Content-Disposition', 'attachment; filename="file.xlsx"');

    $stream = fopen('php://memory', 'r+');
    fwrite($stream, file_get_contents($excelFileName););
    rewind($stream);

    return $response->withBody(new \Slim\Http\Stream($stream));
}