I know, there are lot's of questions here sbout improving PHPExcel performance. But all of them are about writing data, and my problem is in reading.
My function:
function parse($filename){
$objPHPExcel = PHPExcel_IOFactory::load($filename);
$activeSheet = $objPHPExcel->getActiveSheet();
$parsedData = array();
$columnHeaders = array('order', 'ts', 'summ', 'name', 'quant', 'price', 'bccu');
foreach ($activeSheet->getRowIterator() as $rkey => $row) {
$cellIterator = $row->getCellIterator();
foreach ($cellIterator as $ckey => $cell) {
$parsedData[$columnHeaders[$ckey]] = $cell->getCalculatedValue();
}
}
return $parsedData;
}
The file contains ~300 rows and 7 columns. And this script fails to run in 30 seconds.
How can i improve it?
edit:
used
$objReader = PHPExcel_IOFactory::createReader("Excel2007");
$objPHPExcel = $objReader->load($filename);
whth no success
If your columns are already defined, what about remove the column iterator?
Try something like this:
foreach ($activeSheet->getRowIterator() as $rkey => $row) {
$rowIndex = $row->getRowIndex ();
$parsedData[$rowIndex]['order'] = $activeSheet->getCell('A' . $rowIndex);
$parsedData[$rowIndex]['ts'] = $activeSheet->getCell('B' . $rowIndex);
$parsedData[$rowIndex]['summ'] = $activeSheet->getCell('C' . $rowIndex);
.
.
.
}
Try disabling the garbage collector before running parse() by issuing gc_disable(). Guessing that levels of iterations here don't get optimized properly by PHP.
If you're not going to change the file's contents; setting the reader to read-only gives about 10x boost.
For example:
$objReader = PHPExcel_IOFactory::createReader( 'Excel5' );
$objReader->setReadDataOnly( true );
Related
i have file like this
I want to load only two visible row in this example.
I do not know how I can do it.
$reader = new PHPExcel_Reader_Excel2007();
$excel = $reader->load($_FILES['plik']['tmp_name']);
$data = $excel->getActiveSheet()->toArray(null, true,true,true);
When loading the file in PHPExcel shows all 8769 rows.
I have to do it in such a way as filtered data will always be different.
Do you know any way to do this?
If you only want visible rows, then you need to write a bit of code that will loop over the rows selecting only those that are visible
Something like:
$reader = new PHPExcel_Reader_Excel2007();
$excel = $reader->load($_FILES['plik']['tmp_name']);
$highestColumn = $excel->getActiveSheet()->getHighestColumn();
$data = [];
foreach ($excel->getActiveSheet()->getRowIterator() as $row) {
if ($excel->getActiveSheet()->getRowDimension($row->getIndex())->getVisible()) {
$data[] = $excel->getActiveSheet()
->rangeToArray('A' .$row->getIndex().':'.$highestColumn.$row->getIndex());
}
}
Thanks a lot!
Working great as soon swapped "getIndex ()" to "getRowIndex ()"
$reader = new PHPExcel_Reader_Excel2007();
$excel = $reader->load($_FILES['plik']['tmp_name']);
$data = [];
foreach ($excel->getActiveSheet()->getRowIterator() as $row) {
if ($excel->getActiveSheet()->getRowDimension($row->getRowIndex())->getVisible()) {
$data[] = $excel->getActiveSheet()->rangeToArray('A' .$row->getRowIndex().':'.'BB'.$row->getRowIndex());
}
}
For a school project, I have to collect data from an Excel file uploaded by the user. I am using Symfony2 and have installed a bundle I found on knpbundles, named ExcelBundle. I read that to collect data with it from an Excel file, I should use the createWriter method of my phpExcel object. That is what I have done as shown below.
public function addContactsFromExcelAction(Request $request) {
$uploadDir = '/var/www'.$request->getBasePath().'/uploads/';
//die(var_dump($uploadDir));
$file = $request->files->get('fichierExcel');
$fileName = $file->getClientOriginalName();
$fileSaved = $file->move($uploadDir,$fileName);
$phpExcelObject = $this->get('phpexcel')->createPHPExcelObject($uploadDir.$fileName);
$writer = $this->get('phpexcel')->createWriter($phpExcelObject, 'Excel2007');
}
But the thing is that actually, I do not really know how to use the writer to collect data from the cells of my excel datasheets.
Please, could anyone give me the trick to achieve my goal ?
You can iterate as this Example:
public function xlsAction()
{
$filenames = "your-file-name";
$phpExcelObject = $this->get('phpexcel')->createPHPExcelObject($filenames);
foreach ($phpExcelObject ->getWorksheetIterator() as $worksheet) {
echo 'Worksheet - ' , $worksheet->getTitle();
foreach ($worksheet->getRowIterator() as $row) {
echo ' Row number - ' , $row->getRowIndex();
$cellIterator = $row->getCellIterator();
$cellIterator->setIterateOnlyExistingCells(false); // Loop all cells, even if it is not set
foreach ($cellIterator as $cell) {
if (!is_null($cell)) {
echo ' Cell - ' , $cell->getCoordinate() , ' - ' , $cell->getCalculatedValue();
}
}
}
}
}
More samples here
I am Trying to fill my Excel sheet with the data i filtered through the methods i have made. For now i am getting a sheet but i only have only one row filled not the other it's not getting the data i provide it though my object
I am trying my sheet something similar to this sheet .
i am trying to write code in this part of code :
public function export($Sets,$disp_filter)
{
$objPHPExcel = new PHPExcel();
$objPHPExcel->getProperties()->setTitle("Offic excel Test Document");
$styleArray = array(
'font' => array(
'bold' => true,
'color' => array('rgb' => 'FF0000'),
'size' => 10,
'name' => 'Verdana'
));
$objPHPExcel->getActiveSheet()->getStyle('A1')->applyFromArray($styleArray);
$excel_out = array($this->outputSampleName($Sets));
// var_dump($excel_out);
// exit;
$objPHPExcel->getActiveSheet()->SetCellValue('A1', 'Sample Size and Margin of Error');
$rowCount = 2;
foreach ($excel_out as $key=> $line)
{
$colCount = 'A';
$i=0;
// $line = array($Set['name']);
// $CT = $Set['crossTabs']['base'];
// $Moe = array($CT['sample']['moe']);
foreach($line as $col_value)
{
// var_dump($col_value);
// exit;
$objPHPExcel->getActiveSheet()->setCellValue($colCount.$rowCount, $col_value[$i])
->getStyle($colCount.$rowCount)->applyFromArray($styleArray);
$colCount++;
}
$rowCount++;
$i++;
}
return $objPHPExcel;
}
protected function outputSampleName($Sets)
{
foreach ($Sets as $Set)
{
$CT = $Set['crossTabs']['base'];
$line = array(
$Set['name'],
$CT['sample']['moe'] . '%'
);
$excel_out []= $line;
}
return $excel_out;
}
when i see by var_dump($excel_out)
i have this data structure :
**Please suggest me something how can i get those percentage values in my next row in optimized way.
for now i can only loop through the sample[name] which are (enthusiasts, hunter, new shooters etc. )from that array. **
thanks in advance
Maybe because your array elements are arrays themselves, and you are trying to place these subarrays into cells.
Try setting each element of $line in separate cells:
foreach ($excel_out as $line)
{
$colCount = 'A';
$objPHPExcel->getActiveSheet()
->setCellValue('A'.$rowCount, $line[0])
->setCellValue('B'.$rowCount, $line[1])
->setCellValue('C'.$rowCount, $line[2])
->setCellValue('D'.$rowCount, $line[3])
->setCellValue('E'.$rowCount, $line[4]);
$colCount++;
$rowCount++;
}
Note that the first sub-array in $excel_out has only one element. You may want to store.
You could also use an inner loop to traverse through each $line.
EDIT:
After looking at the code in your answer.
Using inner loop:
oreach ($excel_out as $key=> $line)
{
$colCount = 'A';
$i = 0;
foreach($line as $col_value)
{
// var_dump($col_value);
// exit;
$objPHPExcel->getActiveSheet()->setCellValue($colCount.$rowCount, $col_value[$i]);
//$objPHPExcel->getActiveSheet()->setCellValue('B'.$rowCount, $col_value[1]);
//$objPHPExcel->getActiveSheet()->setCellValue('C'.$rowCount, $col_value[2]);
//$objPHPExcel->getActiveSheet()->setCellValue('D'.$rowCount, $col_value[3]);
//$objPHPExcel->getActiveSheet()->setCellValue('E'.$rowCount, $col_value[4]);
//$objPHPExcel->getActiveSheet()->setCellValue('F'.$rowCount, $col_value[5]);
$colCount++;
$i++;
//$rowCount++;
}
$rowCount++;
// $colCount++;
}
$objPHPExcel->getActiveSheet()->setCellValue($colCount.$rowCount, $line);
Seems like you're writing an array $line into a cell. Should you do a loop from 0 to count($line) to put each element into a cell?
Is it possible to import each line of an XLSX file to a row in a PHP array?
You can use PHPExcel which is available here: https://phpexcel.codeplex.com/releases/view/119187
Here is what I use to read either xls or xlsx to an array:
require_once('/path/to/PHPExcel.php');
$filename = "example.xlsx";
$type = PHPExcel_IOFactory::identify($filename);
$objReader = PHPExcel_IOFactory::createReader($type);
$objPHPExcel = $objReader->load($filename);
foreach ($objPHPExcel->getWorksheetIterator() as $worksheet) {
$worksheets[$worksheet->getTitle()] = $worksheet->toArray();
}
print_r($worksheets);
UPDATE / 2022-02-13:
PhpSpreadsheet has been available for a few years now and has replaced PHPExcel. The following code is more or less the same as above with a couple small improvements:
Converted code to a function or method.
Auto detect filetype.
Added ability to specify how null values, formatting and formulas are handled.
Most importantly, call the destructor and clear memory. Without this last step I was running out of memory all the time after loading large files.
/**
* Create a multidimensional array of worksheets from a filename.
*
* #param mixed $nullValue Value returned in the array entry if a cell doesn't exist
* #param bool $calculateFormulas Should formulas be calculated?
* #param bool $formatData Should formatting be applied to cell values?
*
* #return array
*/
function spreadsheet_to_array($nullValue = null, $calculateFormulas = true, $formatData = false) {
$results = [];
$spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file);
foreach ($spreadsheet->getWorksheetIterator() as $worksheet) {
$results[$worksheet->getTitle()] = $worksheet->toArray($nullValue, $calculateFormulas, $formatData);
}
// save memory
$spreadsheet->__destruct();
$spreadsheet = NULL;
unset($spreadsheet);
return $results;
}
I use this:
include 'simplexlsx.class.php';
$xlsx = #(new SimpleXLSX('myFile.xlsx'));
$data = $xlsx->rows();
You can simplexslx from here.
UPDATE
Apparently the link above doesn't work anymore. You can now use this. (Thanks #Basti)
Problem can be solved using PHPExcel library:
$data = [];
$type = PHPExcel_IOFactory::identify($filepath);
$objReader = PHPExcel_IOFactory::createReader($type);
$objPHPExcel = $objReader->load($filepath);
$rowIterator = $objPHPExcel->getActiveSheet()->getRowIterator();
foreach($rowIterator as $row){
$cellIterator = $row->getCellIterator();
foreach ($cellIterator as $cell) {
$data[$row->getRowIndex()][$cell->getColumn()] = $cell->getCalculatedValue();
}
}
where $filepath - path to your xls or xlsx file.
Yes with phpspreadsheet :
include 'vendor/autoload.php';
if($_FILES["import_excel"]["name"] != '')
{
$allowed_extension = array('xls', 'csv', 'xlsx');
$file_array = explode(".", $_FILES["import_excel"]["name"]);
$file_extension = end($file_array);
if(in_array($file_extension, $allowed_extension))
{
$file_name = time() . '.' . $file_extension;
move_uploaded_file($_FILES['import_excel']['tmp_name'], $file_name);
$file_type = \PhpOffice\PhpSpreadsheet\IOFactory::identify($file_name);
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader($file_type);
$spreadsheet = $reader->load($file_name);
unlink($file_name);
$data = $spreadsheet->getActiveSheet()->toArray();
foreach($data as $row)
{
$insert_data = array(
':test1' => $row[0],
':test2' => $row[1],
':test3' => $row[2],
':test4' => $row[3]
);
};
$query = "
INSERT INTO post
( test1, test2, test3, test4)
VALUES
( :test1, :test2, :test3, :test4)
";
$statement = $connect->prepare($query);
$statement->execute($insert_data);
}
echo "succes";
}else{
echo "only xls,csv,xlsx are allowed";
}
With the new version of PHPSpreadSheet you can simply do that :
use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
/*...*/
$reader = new Xlsx();
$reader->setReadDataOnly(true);
$spreadsheet = $reader->load('upload/file.xls');
$sheet = $spreadsheet->getSheet($spreadsheet->getFirstSheetIndex());
$data = $sheet->toArray();
Just be careful, you have all cells as value. For exemple, date is converted to int so you need to convert it
You can use NumberFormat to see all converter.
Exemple to convert an int cell to date :
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
/*....*/
//$value is an integer of a cell value
$value = 44823
$stringDate = NumberFormat::toFormattedString($value, 'YYYY-MM-DD');
// 2022-09-19 is displayed
echo $stringDate;
Found here : https://blog.programster.org/phpspreadsheet-read-excel-file-to-array
More information in the documentation : https://phpspreadsheet.readthedocs.io/en/latest/topics/reading-files/ https://phpspreadsheet.readthedocs.io/en/latest/
Source code of NumberFormat : https://phpoffice.github.io/PhpSpreadsheet/classes/PhpOffice-PhpSpreadsheet-Style-NumberFormat.html
<?php
require_once 'SimpleXLSX.php';
if ( $xlsx = SimpleXLSX::parse('pricelist.xlsx') ) {
print_r( $xlsx->rows() );
} else {
echo SimpleXLSX::parseError();
}
?>
SimpleXLSX
foreach ($objPHPExcel->getWorksheetIterator() as $worksheet) {
foreach ($worksheet->getRowIterator() as $row) {
$cellIterator = $row->getCellIterator();
$cellIterator->setIterateOnlyExistingCells(false);
// I wish
echo $cellIterator->getCell("A3"); // row: $row, cell: A3
}
}
I'm looking for a similar method which named getCell above or well-writed PHPExcel documentation.
Thanks.
If you have the $row information from RowIterator, you can just easily call:
$rowIndex = $row->getRowIndex ();
$cell = $sheet->getCell('A' . $rowIndex);
echo $cell->getCalculatedValue();
The complete code would be:
foreach($worksheet->getRowIterator() as $row){
$rowIndex = $row->getRowIndex();
$cell = $worksheet->getCell('A' . $rowIndex);
echo $cell->getCalculatedValue();
$cell = $worksheet->getCell('B' . $rowIndex);
echo $cell->getCalculatedValue();
}
This is what I needed:
function coordinates($x,$y){
return PHPExcel_Cell::stringFromColumnIndex($x).$y;
}
implementation:
coordinates(5,7); //returns "E7"
Though one could also do this for A-Z columns:
function toNumber($dest)
{
if ($dest)
return ord(strtolower($dest)) - 96;
else
return 0;
}
function lCoordinates($x,$y){
$x = $toNumber($x);
return PHPExcel_Cell::stringFromColumnIndex($x).$y;
}
implementation:
lCoordinates('E',7); //returns "E7"
Rather than iterate all the Cells in a row, when not use the rangeToArray() method for the row, and then use array_intersect_key() method to filter only the columns that you want:
$worksheet = $objPHPExcel->getActiveSheet();
$highestColumn = $worksheet->getHighestColumn();
$columns = array_flip(array('A','C','E'));
foreach($worksheet->getRowIterator() as $row)
{
$range = 'A'.$row->getRowIndex().':'.$highestColumn.$row->getRowIndex();
$rowData = $worksheet->rangeToArray( $range,
NULL,
TRUE,
TRUE,
TRUE);
$rowData = array_intersect_key($rowData[$row->getRowIndex()],$columns);
// do what you want with the row data
}
EDIT
The latest SVN code introduces a number of new methods to th iterators, including the ability to work with ranges, or set the pointer to specific rows and columns