Skip to content
MNB PHPExcelDeveloper Guide
AI

Production guide

Troubleshoot by Symptom

Start from the error or unexpected result you see, confirm the likely cause, and apply the shortest safe fix.

Level
All levels
Reading time
14 min
Package
Any installed MNB PHPExcel package
Updated
Full packageIndividual packagesError codesProduction guidance
Available sincev2.0.3Last API changev2.0.5Version guide

Find the symptom first#

Class not found#

Symptom

PHP reports that Mnb\PHPExcel\MnbExcel or Mnb\PHPExcel\Format\Xlsx does not exist.

Confirm and fix
  1. Run composer show mnb/* in the same project directory as the failing script.
  2. Confirm the script requires the project’s vendor/autoload.php.
  3. Use MnbExcel only with the full package; use Format\Xlsx with the individual XLSX package.
Terminal
composer show mnb/*
composer dump-autoload -o

Composer has old code#

Symptom

GitHub main contains a fix, but the installed package still shows the previous implementation.

Confirm and fix
  1. Check the installed and locked versions with composer show.
  2. Remember that a published tag is immutable; commits added after v2.0.0 are not part of that release.
  3. Publish a new patch tag and update the package with dependencies.
Terminal
composer show mnb/mnb-phpexcel-core
composer show mnb/mnb-phpexcel-core --locked
composer update mnb/mnb-phpexcel-core -W

XMLReader or libxml error#

Symptom

The stack mentions Support\Xml\XmlReader, isEmptyElement, or “Failed to read property due to libxml error”.

Confirm and fix
  1. Verify the installed Core version contains the native XMLReader initialization fix.
  2. Check php -m for libxml and preferably xmlreader.
  3. Confirm Apache and the command-line terminal use the same PHP installation.
verify-core-fix.php
$path = 'vendor/mnb/mnb-phpexcel-core/src/Support/Xml/XmlReader.php';

$source = file_get_contents($path);
var_dump(str_contains($source, 'resetPublicState'));

Worksheet selection fails#

Symptom

You see an empty-name, zero-index, or worksheet-not-found exception.

Confirm and fix
  1. Call sheetNames() before assuming a visible worksheet name.
  2. Use sheet(1) for the first worksheet; worksheet numbers are 1-based.
  3. Use sheetIfExists() for optional input or sheetOrActive() when null/empty input should select the active worksheet.
safe-sheet-selection.php
$workbook = MnbExcel::read($path);
print_r($workbook->sheetNames());

$sheet = $workbook->sheetIfExists($requestedSheet)
    ?? $workbook->activeSheet();

No rows are returned#

Symptom

The workbook opens, but rows() yields nothing or toArray() returns [].

Confirm and fix
  1. Confirm the selected worksheet and physical header row.
  2. Temporarily remove limits, ranges, filters, and projections.
  3. Use structured output to compare source records, empty rows, header rows, and returned rows.
inspect-row-counts.php
$data = $sheet->toStructuredSheetArray([
    'header_row' => 1,
    'skip_empty_rows' => true,
    'row_format' => 'flat',
]);

print_r($data['summary']['row_counts']);

Method called on array#

Symptom

PHP reports “Call to a member function isEmpty() on array” or a similar programming error.

Confirm and fix
  1. toArray() and toStructuredSheetArray() are terminal methods.
  2. Call isEmpty(), hasRows(), or rows() on ReadSession before conversion.
  3. After conversion, use native array checks such as $rows === [].
correct-session-boundary.php
$session = $sheet->withHeaderRow(1);

if ($session->isEmpty()) {
    return;
}

$rows = $session->toArray();

Row counts look wrong#

Symptom

The physical row number, stored row count, skipped rows, and final array count do not match.

Confirm and fix
  1. total includes logical positions and sparse row gaps.
  2. source_records counts rows physically represented in the source.
  3. returned is the final business-row count after header and empty-row processing.
CountMeaning
totalLogical row positions from the first through last selected row.
source_recordsRows physically represented by source records.
emptyExplicit empty records plus implicit sparse gaps.
skipped_emptyExplicit empty records removed by the active option.
headerHeader rows consumed before business data is returned.
returnedFinal rows available in $data['rows'].

Memory limit exceeded#

Symptom

PHP stops with an allowed-memory-size error while reading a large workbook.

Confirm and fix
  1. Use rows() or chunks(), not toArray().
  2. Select only required columns and set a row range or maximum rows.
  3. Enable ext-zip and ext-xmlreader for the native forward-only XLSX path.
bounded-memory-read.php
$session = MnbExcel::read($path)
    ->sheet('Orders')
    ->withHeaderRow(1)
    ->selectColumns(['Order ID', 'Customer', 'Amount']);

foreach ($session->chunks(1000) as $rows) {
    processBatch($rows);
}

Downloaded XLSX is corrupt#

Symptom

Excel reports that the downloaded file is damaged, or the file begins with HTML/error text.

Confirm and fix
  1. Save and validate the workbook before sending HTTP headers.
  2. Clear output buffers so notices, whitespace, and templates cannot precede the binary bytes.
  3. Send the exact content type and length, stream the file, then exit.
download.php
while (ob_get_level() > 0) {
    ob_end_clean();
}

header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Length: ' . filesize($path));
header('Content-Disposition: attachment; filename="report.xlsx"');
readfile($path);
exit;