Selective download with PHPExcel - php

I'm using PHPExcel to download some data stored in MySQLi. I made an algorithm that is working for every data base (in theory). I have tested it with some of them and it was working fine.
I extracted names of the columns in an array: column_names and then, I'm adding titles and data to the excel report.
// Adding titles
$objPHPExcel->setActiveSheetIndex(0)
->setCellValue('A1',$bigTitle);
$counter = 0;
$let = 'a';
while ($counter <= count($column_names)){
$objPHPExcel->setActiveSheetIndex(0)
->setCellValue(strtoupper($let).'3', $column_names[$counter]);
$let++;
$counter++;
}
//Adding data
$i = 4;
while ($row = $result->fetch_array()) {
$counter = 0;
$let = 'a';
while ($counter <= count($column_names)){
$objPHPExcel->setActiveSheetIndex(0)
->setCellValue(strtoupper($let).$i, $row[$column_names[$counter]]);
$let++;
$counter++;
}
$i++;
}
I'm connecting to the database using
$conexion = new mysqli('localhost','user','pass','SAT_dbname',21);
I cloned "SAT_db1" database to "SAT_db2". They have exactly the same structure but different information. The download is working if I'm using
$conexion = new mysqli('localhost','user','pass','SAT_db1',21);
But it's not working if I'm using
$conexion = new mysqli('localhost','user','pass','SAT_db2',21);
I don't know what is wrong if they're the same with different names. Is not PHPExcel working with cloned databases? What else could it be?
The error shows up in the browser as "File not found".
EDIT
I was testing the download all day and I finally found something: I can download when I have few registers. When I have a few more, I can't.
I'm sending the file to the browser:
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment;filename="Report.xlsx"');
header('Cache-Control: max-age=0');
$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007');
$objWriter->save('php://output');
Still haven't found a solution.

PHPExcel has limits with cache. I had to change these limits manually. I used this code before creating PHPExcel object:
set_time_limit(0) ;
$cacheMethod = PHPExcel_CachedObjectStorageFactory:: cache_to_phpTemp;
$cacheSettings = array( 'memoryCacheSize' => '500MB');
PHPExcel_Settings::setCacheStorageMethod($cacheMethod, $cacheSettings);
I assume if you have bigger files, you can expand "memoryCacheSize".

Related

PHPExcel how to solve the encoding issue when reading a file

I was working on an Yii2 API where i need to upload a .csv or .xlsx file and read from it using PHPExcel(DEPRECATED now , but i am stuck with it as new one PhpSpreadsheet requires PHP version 5.6 or newer) and return the array of data .
This was the code used in the API function
public function actionUpload()
{
$params = $_FILES['uploadFile'];
if($params)
{
$data = array();
$model = new UploadForm();
$model->uploadFile = $_FILES['uploadFile'];
$file = UploadedFile::getInstanceByname('uploadFile');
$inputFileName = $model->getpath($file,$data);
// Read your Excel workbook
try
{
$inputFileType = \PHPExcel_IOFactory::identify($inputFileName['link']);
$objReader = \PHPExcel_IOFactory::createReader($inputFileType);
if($inputFileType == 'CSV')
{
if (mb_check_encoding(file_get_contents($inputFileName['link']), 'UTF-8'))
{
$objReader->setInputEncoding('UTF-8');
}
else
{
$objReader->setInputEncoding('Windows-1255');
//$objReader->setInputEncoding('ISO-8859-8');
}
}
$objPHPExcel = $objReader->load($inputFileName['link']);
}
catch(Exception $e)
{
die('Error loading file "'.pathinfo($inputFileName['link'],PATHINFO_BASENAME).'": '.$e->getMessage());
}
// Get worksheet dimensions
$sheet = $objPHPExcel->getSheet(0);
$highestRow = $sheet->getHighestRow();
$highestColumn = $sheet->getHighestColumn();
$fileData = array();
// Loop through each row of the worksheet in turn
for ($row = 1; $row <= $highestRow; $row++)
{
// Read a row of data into an array
$rowData = $sheet->rangeToArray('A' . $row . ':' . $highestColumn . $row,
NULL,
TRUE,
FALSE);
array_push($fileData,$rowData[0]);
// Insert row data array into your database of choice here
}
return $fileData;
}
}
But there are encoding issues when we upload a excel file containing hebrew data in it . As you can see the code below from the above code was used to address this issue
if (mb_check_encoding(file_get_contents($inputFileName['link']), 'UTF-8'))
{
$objReader->setInputEncoding('UTF-8');
}
else
{
$objReader->setInputEncoding('Windows-1255');
}
Later i found that UTF-8 and Windows-1255 are not the only possible encoding for the flies that may be uploaded but other encoding like UTF-16 or other ones depending upon the Operating System of user. Is there any better way to find the encoding other than using mb_check_encoding
The common error that occur during the process of reading the data in file is :
iconv(): Detected an illegal character in input string
As you can see the above error occurs due to the inability to detect the appropriate encoding of the file. Is there any workaround ?
You can attempt to use mb_detect_encoding to detect the file encoding but I find that results vary. You might have to manually specify a custom match order of encodings to get proper results. Here is an example substitute for the if statement in question:
if(inputFileType == 'CSV')
{
// Try to detect file encoding
$encoding = mb_detect_encoding(file_get_contents($inputFileName['link']),
// example of a manual detection order
'ASCII,UTF-8,ISO-8859-15');
$objReader->setInputEncoding($encoding);
}
Make sure the first clean the output buffer in your page:
ob_end_clean();
header( "Content-type: application/vnd.ms-excel" );
header('Content-Disposition: attachment; filename="uploadFile.xls"');
header("Pragma: no-cache");
header("Expires: 0");
ob_end_clean();

PHPExcel Clone Worksheet - Efficient use of memory

I need to clone the first worksheet a few times, accordingly to the amount of rows, but something may be wrong.
The code is:
public function downloadFile()
{
date_default_timezone_set('America/Sao_Paulo');
if(file_exists("xpto.xlsx")){
$objPHPExcel = PHPExcel_IOFactory::load("xpto.xlsx");
$sheets = 3;//3 is enough to throw the error
for($i = 0; $i<$sheets; $i++){
$objClonedWorksheet = clone $objPHPExcel->getSheet(0);
$objClonedWorksheet->setTitle('Sheet ' . $i);
$objClonedWorksheet->setCellValue('A1', 'Test ' . $i);
$objPHPExcel->addSheet($objClonedWorksheet);
}
$objPHPExcel->setActiveSheetIndex(0);
$filename = 'file.xlsx';
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment;filename="'.$filename.'"');
header('Cache-Control: max-age=0');
$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007');
ob_end_clean();
$ret = $objWriter->save('php://output');
exit;
}
}
But I got an exhausted memory error. Than I tried the most commented solution (that is actually an workaround) that is to add
ini_set('memory_limit', '-1');
I added this line just after the load function and it worked, but I don't think it is a good solution to use on a SaaS application. I don't even think most hosts (AWS, for example) will allow me to use that.
I also tried to clone the sheet before the for loop, but when use addSheet, I realized that this function doesn't create a new object and when I change the name of the sheet (by the second iteration of the for loop), it changes the last sheet created, throwing an "already existing sheet with the same name" error.
Trying to use one of the links #rhazen listed, I changed the for loop to:
$objFromSheet = $objPHPExcel->getSheet(0);
$sheets = 3;
for($i = 1; $i<=$sheets; $i++){
$objToSheet = $objPHPExcel->createSheet($i);
foreach($objFromSheet->getRowIterator() as $row){
$cellIterator = $row->getCellIterator();
$cellFrom = $cellIterator->current();
$cellTo = $objToSheet->getCell($cellFrom->getCoordinate());
$cellTo->setXfIndex($cellFrom->getXfIndex());
$cellTo->setValue($cellFrom->getValue());
}
}
But it seems not to work either. Is there a misunderstanding about Iterator or XfIndex?
The solution is in the edited question. Thanks for those who helped.

exporting large files to excel using PHPExcel

I am trying to export around 40,000 rows of Mysql data in PHP(Laravel4) using PHPExcel library.
Below is my code:
($patList is an array of result columns)
set_time_limit ( 3000 );
$cacheMethod = PHPExcel_CachedObjectStorageFactory:: cache_to_phpTemp;
$cacheSettings = array( 'memoryCacheSize' => -1);
PHPExcel_Settings::setCacheStorageMethod($cacheMethod, $cacheSettings);
$objPHPExcel = new PHPExcel();
$i = 1;
$patList = $result[0];
for ($r = 0; $r < count($patList); $r++) {
$objPHPExcel->setActiveSheetIndex(0)
->setCellValue("A$i", $patList[$r][0])
->setCellValue("B$i", $patList[$r][1])
->setCellValue("C$i", $patList[$r][2])
->setCellValue("D$i", $patList[$r][1])
->setCellValue("E$i", $patList[$r][2])
->setCellValue("F$i", $patList[$r][1])
->setCellValue("G$i", $patList[$r][2])
->setCellValue("H$i", $patList[$r][2])
->setCellValue("I$i", $patList[$r][1])
->setCellValue("J$i", $patList[$r][2])
->setCellValue("K$i", $patList[$r][5]);
$i++;
}
$objPHPExcel->getActiveSheet()->setTitle('Name of Sheet 1');
header('Content-Type: application/vnd.ms-excel');
header('Content-Disposition: attachment;filename="result.xls"');
header('Cache-Control: max-age=0');
ob_clean();
flush();
$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel5');
$objWriter->save('php://output');
The above code runs fine if there are 3-4 columns in the excel and 15,000 rows. However, if I increase the no. of rows to 30,000 or the no. of columns to 10, the excel doesn't get generated.
$cacheSettings = array( 'memoryCacheSize' => -1);
isn't sensible.... I don't even know if using a value of -1 will work; but if it does, it will mean that you're storing everything in memory and nothing in php://temp
The memoryCacheSize value tells the cache stream how much data should be stored in memory before switching data out to php://temp ; so
$cacheSettings = array( 'memoryCacheSize' => '8MB');
would tell the cache stream to use 8MB of memory, and then if additional data needed to be stored to use php://temp instead

PHPExcel Set cell with variable

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;
?>

php + download to excel --> worksheet name

I am currently exporting data from php to excel using the code as below:
include("dbconnect.php");
$query = $_POST['query'];
$result = odbc_exec($conn,$query);
$count = odbc_num_fields($result);
//Define Variable For ODBC
$data = "";
//Field Name Data
for ($i = 1; $i <= $count; $i++)
{
$data .= odbc_field_name($result, $i)."t";
}
$data .= "n";
//Row Data
while(odbc_fetch_row($result))
{
for ($j = 1; $j <= $count; $j++)
{
$data .= odbc_result($result, $j)."t";
}
$data .= "n";
}
header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=ExcelFile.xls;");
header("Pragma: no-cache");
header("Expires: 0");
echo $data;
odbc_close($conn);
This all works fine, but the generated excel file has a sheetname of: ".xls]ExcelFile(1)" , and when you try to rename the sheet it causes an error in excel (unless you save the file first).
How can I define the sheetname in my php file?
Thanks in advance!
Have a nice weekend:-)
You're not actually creating an xls file, but a tab separated value file. Excel can read this, but it simply populates the data in the first worksheet. Because it's not a true xls file, you can't name the worksheet tabs in any way.
One option would be to change your code to use a library that writes true xls files, such as PHPExcel ( http://www.phpexcel.net )... you would then be able to define a name for the worksheet tab within your script.
By changing the
header("Content-type: application/octet-stream");
To
header("Content-type: application/vnd-ms-excel");
It is downloading without any errors and i am able to save that. the worksheet name is same as excel name.

Categories