I am generating an Excel file with an sql query, this so that it shows me all the records, the problem is that it works correctly locally, the excel is generated and downloaded, but when uploading it to the server it sends me to the file where the code is and on screen it shows me strange symbols
This is my code from my file to generate the excel and download it.
<?php
// Declaramos la librerÃa
require __DIR__ . "/../vendor/autoload.php";
// BD
require "../conexion/dbconect.php";
use PhpOffice\PhpSpreadsheet\{Spreadsheet, IOFactory};
$query = "SELECT * FROM siacc_usuarios";
$resultado = $con->query($query);
$excel = new Spreadsheet();
$activeSheet = $excel->getActiveSheet();
//set default font
$excel->getDefaultStyle()
->getFont()
->setName('Arial')
->setSize(10);
$excel->getActiveSheet()->getStyle('A1:V1')->getFont()->setBold(true);
$activeSheet->setTitle("usuarios");
$activeSheet->getColumnDimension('A')->setwidth(10);
$activeSheet->setCellValue('A1', 'ID Usuario');
$activeSheet->getColumnDimension('B')->setwidth(10);
$activeSheet->setCellValue('B1', 'CEC');
$activeSheet->getColumnDimension('C')->setwidth(80);
$activeSheet->setCellValue('C1', 'Adscripcion');
$activeSheet->getColumnDimension('D')->setwidth(20);
$activeSheet->setCellValue('D1', 'Numero Empleado');
$activeSheet->getColumnDimension('E')->setwidth(20);
$activeSheet->setCellValue('E1', 'Apellido Paterno');
$i = 2;
while($row = $resultado->fetch_assoc()) {
$activeSheet->setCellValue('A'.$i , $row['id_usuario']);
$activeSheet->setCellValue('B'.$i , $row['cec']);
$activeSheet->setCellValue('C'.$i , $row['adscripcion']);
$activeSheet->setCellValue('D'.$i , $row['emp']);
$activeSheet->setCellValue('E'.$i , $row['ape_pat']);
$i++;
}
$filename = 'usuarios.xlsx';
// redirect output to client browser
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment;filename="'.$filename.'"');
header('Cache-Control: max-age=0');
$writer = IOFactory::createWriter($excel, 'Xlsx');
ob_end_clean();
$writer->save('php://output');
This is what it shows me on screen:
Related
i want to download a file of projet but i get it empty. i'am using a spreadsheet librairy
Notice : i a make a dump after save function , my file is full and not empty in the path directory of project
Someone can help me !
bellow is my code :
$spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load('template.xlsx');
$worksheet = $spreadsheet->getActiveSheet();
$filename = 'write.xls';
$worksheet->getCell('A1')->setValue('John');
$worksheet->getCell('A2')->setValue('Smith');
$writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet, 'Xls');
$writer->save($filename); die;
// to download file
header('Content-Type: application/vnd.ms-excel');
header("Content-Length:".filesize($filename));
header("Content-Disposition: attachment;filename=$filename");
header('Cache-Control: max-age=0');
$writer->save('php://output');
exit();
i except a full file after downloading it
This function would work:
define ("ONE_DAY", 86400);
function getExisting()
{
$rootFolder = "pathTodirectory";
//first clear old files
$files = scandir($rootFolder,1);
array_pop($files); array_pop($files);
foreach($files as $file)
{
$fp = $rootFolder . DIRECTORY_SEPARATOR . $file;
$filemtime=filemtime($fp);
if (time() - $filemtime >= (2 * ONE_DAY))unlink($fp);
}//end clearing old files
//second rescan folder for current files
$files = scandir($rootFolder,1);
array_pop($files); array_pop($files);
$existing = array_reverse($files);
return $existing;
}
$existing = getExisting();
echo "\n<p> Select file or enter office number to review inventory:";
echo "\n <ul>";
foreach($existing as $rpt)
{
$spd = "pathTodirectory" . $rpt; \\make sure to follow up with relative path name here also
echo "\n <li><a href=\"$spd\" >" . $rpt ."</a></li>";
}
echo "\n </ul>";
I think it is the load() usage issue, your code works with following correction in my site :
$file_loc = 'template.xlsx';
$file_type = \PhpOffice\PhpSpreadsheet\IOFactory::identify($file_loc);
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader($file_type);
// $spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load('template.xlsx');
$spreadsheet = $reader->load($file_loc);
$worksheet = $spreadsheet->getActiveSheet();
$filename = 'write.xls';
$worksheet->getCell('A1')->setValue('John');
$worksheet->getCell('A2')->setValue('Smith');
$writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet, 'Xls');
// save a physical file in server, you can skip this actually
$writer->save($target_dir . $filename);
// die; // don't die, be happy (^_^)
// to download file
header('Content-Type: application/vnd.ms-excel');
header("Content-Length:" . filesize($filename));
header("Content-Disposition: attachment;filename=$filename");
header('Cache-Control: max-age=0');
$writer->save('php://output');
exit();
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.
If I export it as .csv, then it works. But I need it as .xls or .xlsx
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.
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()
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();
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);
call ob_end_clean(); just before the $writer->save('php://output').
ob_end_clean();
$writer->save('php://output');
This worked for me:
$excel = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
$sheet = $excel->getActiveSheet();
$sheet->setTitle('This is a test', true);
ob_end_clean();
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment;filename="filename_' . time() . '.xlsx"');
header('Cache-Control: max-age=0');
$xlsxWriter = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($excel, 'Xlsx');
$xlsxWriter = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($excel);
exit($xlsxWriter->save('php://output'));
If you have problems where the files download corrupted, it is always good to check if there is any extra whitespace at the top of your file output. If your PHP files have blank white lines, whilst HTML won't have a problem, your phpspreadsheet file will. Spent a good chunk of time trying to fix these issues but the problem was with the whitespace!
I have a button on a modal and when clicked I want to generate an Excel workbook based off of a xls template file and then prompt it for the user to download/open.
The button uses javascript to open a new blank window
The click event simply does
var tsUrl = baseUrl + 'index.php?r=office/gen-t-s-xls&proj='+projNo+'&leg='+legNo+'&driver='+driverId;
var win = window.open(tsUrl, '_blank');
and calls the following controller Action
public function actionGenTSXls($proj, $leg, $driver){
// https://phpspreadsheet.readthedocs.io/en/develop/topics/recipes/
if(!is_numeric($proj) || !is_numeric($leg) || !is_numeric($driver)){
echo 'Invalid entry.';
die();
}
//Get the Project Model
$model = Projects::find()
->where(['=', 'ProjNo', $proj])
->one();
if (!$model) {
echo "There was a problem with the submitted request. (1)";
die();
}
//Get the Project Leg Model
$modelLeg = ProjectsLegs::find()
->where(['=', 'ProjId', $model->ProjId])
->andWhere(['=', 'LegNo', $leg])
->andWhere(['=', 'DriverId', $driver])
->one();
if (!$modelLeg) {
echo "There was a problem with the submitted request. (2)";
die();
}
$timestamp = date('Ymd\THis'); // Date/Time stamp
$filename = 'TripSheet_'.$model->ProjNo.'_'.$modelLeg->LegId.'_'.$timestamp.'.xls';
if(YII_ENV_DEV){
$filepath = Yii::$app->basePath.'\web\files\excel\\';
}else{
$filepath = \Yii::getAlias('#webroot').'/files/excel/';
}
$file = $filepath . $filename;
header('Content-Type: application/vnd.ms-excel');
header('Content-Disposition: attachment;filename="'.$filename.'"');
header('Cache-Control: max-age=0');
$sFile = Yii::$app->basePath.DIRECTORY_SEPARATOR.'templates'.DIRECTORY_SEPARATOR.'TS_Tmplt.xlsx';
$spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load( $sFile );
$spreadsheet->getProperties()
->setCreator("TS")
->setLastModifiedBy(User::findOne(Yii::$app->user->getId())->Dispatcher)
->setTitle("TS ".$model->ProjNo.'_'.$modelLeg->LegId)
->setSubject("TS ".$model->ProjNo.'_'.$modelLeg->LegId)
->setDescription("TS ".$model->ProjNo.'_'.$modelLeg->LegId);
//working on something with the spreadsheet/worksheet
$sheet = $spreadsheet->getSheetByName('Sheet1');
//Date
$sheet->setCellValue('K3', date("n/j/Y"));
$sheet->getStyle('K3')
->getNumberFormat()
->setFormatCode('m/d/yy');
//Order
if(!is_null($model->ProjNo)){$sheet->setCellValue('K4', $model->ProjNo);}
//Carrier Order
if(!is_null($model->CompTripNo)){
$sheet->setCellValue('K5', $model->CompTripNo);
$sheet->getStyle('K5')->getAlignment()->setShrinkToFit(true);
}
//Dispatcher
if(!is_null($model->DispatcherId)){$sheet->setCellValue('J11', User::findOne($modelLeg->DispatcherId)->Dispatcher);}
//Company Name
if(!is_null($model->ClientId)){
$sheet->setCellValue('E4', Clients::findOne($model->ClientId)->Company);
$sheet->getStyle('E4')->getAlignment()->setShrinkToFit(true);
}
//Start Date
if(!is_null($modelLeg->StartDt)){
$date = \DateTime::createFromFormat('Y-m-d H:i:s', $modelLeg->StartDt);
$cellVal = $date->format("n/j/Y g:i A");
$sheet->setCellValue('E8', $cellVal);
}
$writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet, 'Xls');
$writer->save('php://output');
}
Now, in a general sense, it works. It create the xls, the user is prompted to open/download. But it generates an error in my yii log.
[error][yii\web\HeadersAlreadySentException] exception
'yii\web\HeadersAlreadySentException' with message 'Headers already
sent
I've looked at countless similar thread, and tried all sorts of permutations involving
ob_start();
if (ob_get_length()) ob_end_clean();
if (ob_get_contents()) ob_end_clean();
//etc...
nothing seems to get me around my current issue.
I've been turning in circles for quite some time (not a lack of trying, doing research, ...) and thought I'd get some experts advice and learn. I am a novice, so if you can explain so I can learn it would be greatly appreciated.
Update 1
I decided to simplify my code to see what the issue was, so I generated the xls file, so I could temporarily eliminate that code and even so, with only 7 lines of code, I get the same error!
public function actionDownload(){
$filename = "TS.xls";
$file = "C:\Users\Dev\Downloads\TS.xls";
$spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load( $file );
$writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter( $spreadsheet, 'Xls');
header('Content-Type: application/vnd.ms-excel');
header('Content-Disposition: attachment;filename="'.$filename.'"');
$writer->save("php://output");
}
Update 2 / Workaround
Did more Googling, and found a posting that I tried. By adding die(); at the very end of my action, the error goes away?! Can someone explain. I'm assuming this is not a proper solution though even if it does appear to work.
Update 3 / Solution
This ended up being the proper way to handle this
replace the following part of the code
header('Content-Type: application/vnd.ms-excel');
header('Content-Disposition: attachment;filename="'.$filename.'"');
$writer->save("php://output");
with
$response = Yii::$app->getResponse();
$headers = $response->getHeaders();
$headers->set('Content-Type', 'application/vnd.ms-excel');
$headers->set('Content-Disposition', 'attachment;filename="'.$filename.'"');
$headers->set('Cache-Control: max-age=0');
ob_start();
$writer->save("php://output");
$content = ob_get_contents();
ob_clean();
return $content;
and a big thank you to all of you for taking the time to try and help me. Your time and efforts are greatly appreciated!
Right before your first header call add:
ob_end_clean(); // clear out anything that may have already been output
Your code would look something like:
$file = $filepath . $filename;
ob_end_clean(); // clear out anything that may have already been output
header('Content-Type: application/vnd.ms-excel');
header('Content-Disposition: attachment;filename="'.$filename.'"');
header('Cache-Control: max-age=0');
I have the following script
$this->load->library('excel');
$filename = FCPATH.'assets/template/monthly_report.xlsx';
$filetype = PHPExcel_IOFactory::identify($filename);
$objReader = PHPExcel_IOFactory::createReader($filetype);
$objReader->setIncludeCharts(TRUE);
$this->objExcel = $objReader->load($filename);
$this->objExcel->setActiveSheetIndex(0);
$sheet = $this->objExcel->getActiveSheet();
$sheet->setCellValue('A3', $process->process_name);
$last_num = 2; // row terakhir
$last_num_counter = 2; // row terakhir untuk counter
for($i = 4; $i <= $date_max + 3; $i++){
$cell = $this->translate_cell($i);
$sheet->setCellValue($cell.'2', date(($i - 3).'-M'));
}
foreach($schedules as $schedule){
}
$filename='Laporan Bulanan.xlsx';
header('Content-Type: application/vnd.ms-excel'); //mime type
header('Content-Disposition: attachment;filename="'.$filename.'"'); //tell browser what's the file name
header('Cache-Control: max-age=0'); //no cache
// PHPExcel_Settings::setZipClass(PHPExcel_Settings::PCLZIP);
$objWriter = PHPExcel_IOFactory::createWriter($this->objExcel, $filetype); //Excel2007
$objWriter->setIncludeCharts(TRUE);
$objWriter->save('php://output');
the script is loading an xlsx file as a template, the template itself contain a graph/chart. so, all I have to do is replace data in cells and then save it, without any touch to the chart stuff and then save it. but, it produce error in the begining of the generated xlsx file, it said
<p>Severity: Warning</p>
<p>Message: PHPExcel_Reader_Excel2007_Chart::getAttribute(): Node no longer exists</p>
<p>Filename: Excel2007/Chart.php</p>
<p>Line Number: 40</p>
I have no idea about that error, please somebody save my day.
I have this test script that is acting just like my production script except production script pulls from a SQL db. I want to set the cell placement using a variable based off the count of an array. In the script below, (which you can copy and run as an example) I want to set the cell number based off how many of the same car that is in an array. So for an example there are 7 BMW's listed in the array. So I want the Comments: data copied to cell A12 using the code $num=$no+5; $cell='A'.$num;
The problem I am having is it does place it on that line but it also places it 7 more times about it. If there are 4 cars of that type it would place it on the right line but also place it 3 times above it. I just want it to place it once at the desired location. Any help would be great. Here is the code:
<?PHP
require_once 'Classes/PHPExcel.php';
include 'Classes/PHPExcel/Writer/Excel2007.php';
$dataArray= array();
$cars=array("Versa","Volt","Volt","Volt","Volt","Volkswagen","Bentley","Benz","BMW","BMW","BMW","BMW","BMW","BMW","BMW","Cobra","Cord","Daewoo","Datsun","Dodge","Dodge","Dixi");
$objPHPExcel = new PHPExcel();
$objPHPExcel->setActiveSheetIndex(0);
while (list($var, $val) = each($cars)) {
if ($val!=$id){
$dataArray = array();
$objWorksheet = new PHPExcel_Worksheet($objPHPExcel);
$objPHPExcel->addSheet($objWorksheet);
$objWorksheet->setTitle(''. $val);
$row_array[$val] = $val;
array_push($dataArray,$row_array);
$no = count($dataArray);
$num=$no+5;
$cell='A'.$num;
$objWorksheet->setCellValue('A1' , $no);
$objWorksheet->setCellValue('A2' , $val);
$objWorksheet->setCellValue($cell , 'Comments:');
$id = $val;
}
else {
$row_array[$val] = $val;
$count=count($cars);
$count2=count($loc);
array_push($dataArray,$row_array);
$no = count($dataArray);
$num=$no+5;
$cell='A'.$num;
$objWorksheet->setCellValue('A2' , $no);
$objWorksheet->setCellValue('A3' , $val);
$objWorksheet->setCellValue($cell , 'Comments:');
$id = $val;
}
}
// Save Excel 2007 file
#echo date('H:i:s') . " Write to Excel2007 format\n";
$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007');
ob_end_clean();
// We'll be outputting an excel file
header('Content-type: application/vnd.ms-excel');
// It will be called file.xls
header('Content-Disposition: attachment; filename="cars.xlsx"');
$objWriter->save('php://output');
Exit;
?>
This fixes the problem.
<?PHP
require_once 'Excel/PHPExcel.php';//path for my config, rewrite for yours
//include 'Classes/PHPExcel/Writer/Excel2007.php'; // not needed, lazy loader job
$cars=array("Versa","Volt","Volt","Volt","Volt","Volkswagen","Bentley","Benz","BMW","BMW","BMW","BMW","BMW","BMW","BMW","Cobra","Cord","Daewoo","Datsun","Dodge","Dodge","Dixi");
$objPHPExcel = new PHPExcel();
$objWorksheet=$objPHPExcel->setActiveSheetIndex(0);
$id='';
$countRows=0;
while (list($var, $val) = each($cars)) {
if ($val!=$id && $id!=''){
$objWorksheet->setTitle($id);
$num=$countRows+5;
$cell='A'.$num;
$objWorksheet->setCellValue($cell , 'Comments:');
$objWorksheet = new PHPExcel_Worksheet($objPHPExcel);
$objPHPExcel->addSheet($objWorksheet);
$id = $val;
$countRows=0;
}//end if
if($id=='') $id=$val;//the first car
$no = ++$countRows;
$objWorksheet->setCellValue('A'.$no , $no);
$objWorksheet->setCellValue('B'.$no , $id);//Versa, Volt, ...
}
if($countRows>0 && $id!=''){// the last car - if $id=='' the workbook is empty
$objWorksheet->setTitle($id);
$num=$countRows+5;
$cell='A'.$num;
$objWorksheet->setCellValue($cell , 'Comments:');
}//end if
// Save Excel 2007 file
$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007');
ob_end_clean();
// We'll be outputting an excel file
header('Content-type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); // note : use correct mime type (not xls for xlsx)
// It will be called cars.xlsx
header('Content-Disposition: attachment; filename="cars.xlsx"');
$objWriter->save('php://output');
Exit;
?>