How to find out how many rows and columns to read from an Excel file with PHPExcel?

StackOverflow https://stackoverflow.com/questions/4562527

  •  14-10-2019
  •  | 
  •  

Question

With the following code, I am able to read the cells out of an Excel file with PHPExcel.

I currently manually define how many rows and columns to read.

Is there a way that PHPExcel can tell me how many rows and columns I have to read to get all the data out of the worksheet, e.g. even if some rows and columns are left blank?

$file_name = htmlentities($_POST['file_name']);
$sheet_name = htmlentities($_POST['sheet_name']);
$number_of_columns = htmlentities($_POST['number_of_columns']);
$number_of_rows = htmlentities($_POST['number_of_rows']);

$objReader = PHPExcel_IOFactory::createReaderForFile("data/" . $file_name);
$objReader->setLoadSheetsOnly(array($sheet_name));
$objReader->setReadDataOnly(true);
$objPHPExcel = $objReader->load("data/" . $file_name);

echo '<table border="1">';
for ($row = 1; $row < $number_of_rows; $row++) {
    echo '<tr>';
    for ($column = 0; $column < $number_of_columns; $column++) {
        $value = $objPHPExcel->setActiveSheetIndex(0)->getCellByColumnAndRow($column, $row)->getValue();
        echo '<td>';
        echo $value . '&nbsp;';
        echo '</td>';
    }
    echo '</tr>';
}
echo '</table>';

Solution:

Thanks, Mark, here's the full solution with those functions:

$file_name = htmlentities($_POST['file_name']);
$sheet_name = htmlentities($_POST['sheet_name']);
$number_of_columns = htmlentities($_POST['number_of_columns']);
$number_of_rows = htmlentities($_POST['number_of_rows']);

$objReader = PHPExcel_IOFactory::createReaderForFile("data/" . $file_name);
$objReader->setLoadSheetsOnly(array($sheet_name));
$objReader->setReadDataOnly(true);

$objPHPExcel = $objReader->load("data/" . $file_name);

$highestColumm = $objPHPExcel->setActiveSheetIndex(0)->getHighestColumn();
$highestRow = $objPHPExcel->setActiveSheetIndex(0)->getHighestRow();

echo 'getHighestColumn() =  [' . $highestColumm . ']<br/>';
echo 'getHighestRow() =  [' . $highestRow . ']<br/>';

echo '<table border="1">';
foreach ($objPHPExcel->setActiveSheetIndex(0)->getRowIterator() as $row) {
    $cellIterator = $row->getCellIterator();
    $cellIterator->setIterateOnlyExistingCells(false);
    echo '<tr>';
    foreach ($cellIterator as $cell) {
        if (!is_null($cell)) {
            $value = $cell->getCalculatedValue();
            echo '<td>';
            echo $value . '&nbsp;';
            echo '</td>';
        }
    }
    echo '</tr>';
}
echo '</table>';

alt text

Was it helpful?

Solution

$objPHPExcel->setActiveSheetIndex(0)->getHighestColumn();

and

$objPHPExcel->setActiveSheetIndex(0)->getHighestRow();

or

$objPHPExcel->setActiveSheetIndex(0)->calculateWorksheetDimension();

which returns a range as a string like A1:AC2048

although trailing blank rows and columns are included in these.

EDIT

or you can use the iterators to loop through the existing rows and columns to get each cell within the worksheets used range. See /Tests/28iterator.php in the production distribution for an example. The iterators can be set to ignore blanks.

OTHER TIPS

From the 1.7.6 and below PHPExcel versions it is possible to get worksheet information without reading whole file:

$objReader     = PHPExcel_IOFactory::createReader("Excel2007"); 
$worksheetData = $objReader->listWorksheetInfo($uploadedfile);
$totalRows     = $worksheetData[0]['totalRows'];
$totalColumns  = $worksheetData[0]['totalColumns'];

You can do it much less cell reads than itterating all the rows(columns).

In my case, the first column is SKU of item and it's mandatory.

If you expect file with many many rows, in my case it can be 100 000 rows or more, i'm reading the value of the first column at every 10 000 row.

If cell A10000 is not empty, read A20000 and so on.

In this way, for a file with 100 000 rows I need max 10 reads of a single cell to decide in which segment of 10 000 rows the file ends.

For example, let say it's between 30 000 and 40 000 row.

Now get the average from above value - 35 000. One read of cell A35000 will further reduce the scope to 5000 rows. Next average (and the single cell read) will further reduce the scope to 2500 and so on.

Approximately you will need around 13-14 single cell reads, if you know in which 10 000 segment is the end of the file. If you expect file with 100 000 rows add maximum 10 cell reads to determine the exact segment of 10 000 rows. This means maximum of around 25 cell reads for file with 100 000 rows.

Edit: if you expect empty rows - read little more cells, for example, if you expect no more than 1 consequent empty row, read 2 consequent cells every time, for example A10000 and A10001, one of them should be non-empty, or you are beyond the end of the file. If you expect no more than 2 consequent empty rows, read 3 cells every time, for example A10000, A10001 and A10002, and so on.

I don't think you can do that, you would have to loop through starting from say 1000 and go backwards until you hit the first non-blank cell and that would be your last row or column.

You can write a macro to do this in excel which may help but I don't know if you can execute it with PHPExcel.

Following @nikolay's thinking from answer above, I decided to make the first cell of every row mandatory. That way, I just look at each cell of each row first to find out how many rows actually have data, depending on the first row.

$uploadedfile = \PHPExcel_IOFactory::load(Yii::getAlias('uploads').'/'.$file_location);
$uploadeddata = $uploadedfile->getActiveSheet()->toArray(null, true, true, true);

    //we need to first know how many rows actually have data
    //my first two rows have column labels, so i start with the third row.
    $row_count = 3;
    // read through the data and see how many rows actually have data
    //the idea is that for every row, the first cell should be mandatory...
    //if we find one that is not, we stop there...
    do
    {
      $row_count++;
    } while($uploadeddata[$row_count]['A'] == "null");

    //get the actual number of rows with data, removing the column labels
    $actual_rows = $row_count-3;
$spreadsheet = new Spreadsheet();
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader('xls');
$reader->setReadDataOnly(true);
$spreadsheet = $reader->load('file location here');
$worksheet = $spreadsheet->getActiveSheet();
foreach ($worksheet->getRowIterator() AS $row) {
     $cellIterator = $row->getCellIterator();
     $cellIterator->setIterateOnlyExistingCells(FALSE); // This loops through all cells,
     $cells = [];
           foreach ($cellIterator as $cell) {
                 $cells[] = $cell->getValue();
           }
     $rows[] = $cells;
}

//blade html
<table class="table table-hover">
      <thead>
            <tr>
                @foreach($rows[0] as $heading)
                     <th>{{$heading}}</th>
                @endforeach
            </tr>
      </thead>
      <tbody>
             @foreach($rows as $key=>$val)
                   @if(!($key == 0))
                        <tr>
                            @foreach($val as $value)
                                 <td>{{$value}}</td>
                            @endforeach
                        </tr>
                    @endif
             @endforeach
      </tbody>
</table>
```
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top