Troubleshoot by Symptom
Start from the error or unexpected result you see, confirm the likely cause, and apply the shortest safe fix.
Updated
What you will learn
- Diagnose problems from the visible symptom rather than an internal class name.
- Confirm whether installed Composer code matches the expected release.
- Choose a safe fix without exposing vendor paths or stack traces to users.
Find the symptom first#
Class not found#
PHP reports that Mnb\PHPExcel\MnbExcel or Mnb\PHPExcel\Format\Xlsx does not exist.
- Run
composer show mnb/*in the same project directory as the failing script. - Confirm the script requires the project’s
vendor/autoload.php. - Use
MnbExcelonly with the full package; useFormat\Xlsxwith the individual XLSX package.
composer show mnb/*
composer dump-autoload -oComposer has old code#
GitHub main contains a fix, but the installed package still shows the previous implementation.
- Check the installed and locked versions with
composer show. - Remember that a published tag is immutable; commits added after
v2.0.0are not part of that release. - Publish a new patch tag and update the package with dependencies.
composer show mnb/mnb-phpexcel-core
composer show mnb/mnb-phpexcel-core --locked
composer update mnb/mnb-phpexcel-core -WXMLReader or libxml error#
The stack mentions Support\Xml\XmlReader, isEmptyElement, or “Failed to read property due to libxml error”.
- Verify the installed Core version contains the native XMLReader initialization fix.
- Check
php -mforlibxmland preferablyxmlreader. - Confirm Apache and the command-line terminal use the same PHP installation.
$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#
You see an empty-name, zero-index, or worksheet-not-found exception.
- Call
sheetNames()before assuming a visible worksheet name. - Use
sheet(1)for the first worksheet; worksheet numbers are 1-based. - Use
sheetIfExists()for optional input orsheetOrActive()when null/empty input should select the active worksheet.
$workbook = MnbExcel::read($path);
print_r($workbook->sheetNames());
$sheet = $workbook->sheetIfExists($requestedSheet)
?? $workbook->activeSheet();No rows are returned#
The workbook opens, but rows() yields nothing or toArray() returns [].
- Confirm the selected worksheet and physical header row.
- Temporarily remove limits, ranges, filters, and projections.
- Use structured output to compare source records, empty rows, header rows, and returned rows.
$data = $sheet->toStructuredSheetArray([
'header_row' => 1,
'skip_empty_rows' => true,
'row_format' => 'flat',
]);
print_r($data['summary']['row_counts']);Method called on array#
PHP reports “Call to a member function isEmpty() on array” or a similar programming error.
toArray()andtoStructuredSheetArray()are terminal methods.- Call
isEmpty(),hasRows(), orrows()onReadSessionbefore conversion. - After conversion, use native array checks such as
$rows === [].
$session = $sheet->withHeaderRow(1);
if ($session->isEmpty()) {
return;
}
$rows = $session->toArray();Row counts look wrong#
The physical row number, stored row count, skipped rows, and final array count do not match.
totalincludes logical positions and sparse row gaps.source_recordscounts rows physically represented in the source.returnedis the final business-row count after header and empty-row processing.
| Count | Meaning |
|---|---|
total | Logical row positions from the first through last selected row. |
source_records | Rows physically represented by source records. |
empty | Explicit empty records plus implicit sparse gaps. |
skipped_empty | Explicit empty records removed by the active option. |
header | Header rows consumed before business data is returned. |
returned | Final rows available in $data['rows']. |
Memory limit exceeded#
PHP stops with an allowed-memory-size error while reading a large workbook.
- Use
rows()orchunks(), nottoArray(). - Select only required columns and set a row range or maximum rows.
- Enable
ext-zipandext-xmlreaderfor the native forward-only XLSX path.
$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#
Excel reports that the downloaded file is damaged, or the file begins with HTML/error text.
- Save and validate the workbook before sending HTTP headers.
- Clear output buffers so notices, whitespace, and templates cannot precede the binary bytes.
- Send the exact content type and length, stream the file, then exit.
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;