PHPOffice/PhpSpreadsheet · error · PhpOffice\PhpSpreadsheet\Reader\Exception
Parameter pos=$pos is invalid.
Error message
Parameter pos=$pos is invalid.
What it means
Thrown by OLERead::getInt4d() when asked to read a 4-byte integer at a negative offset into the OLE data buffer. Offsets in a valid container are non-negative; a negative one means header fields (block counts, start blocks) decoded to nonsense values earlier, which is the signature of a corrupted or hostile file.
Source
Thrown at src/PhpSpreadsheet/Shared/OLERead.php:312
}
// Additional Document Summary information
if ($name == chr(5) . 'DocumentSummaryInformation') {
$this->documentSummaryInformation = count($this->props) - 1;
}
$offset += self::PROPERTY_STORAGE_BLOCK_SIZE;
}
}
/**
* Read 4 bytes of data at specified position.
*/
private static function getInt4d(string $data, int $pos): int
{
if ($pos < 0) {
// Invalid position
throw new ReaderException('Parameter pos=' . $pos . ' is invalid.');
}
$len = strlen($data);
if ($len < $pos + 4) {
$data .= str_repeat("\0", $pos + 4 - $len);
}
// FIX: represent numbers correctly on 64-bit system
// http://sourceforge.net/tracker/index.php?func=detail&aid=1487372&group_id=99160&atid=623334
// Changed by Andreas Rehm 2006 to ensure correct result of the <<24 block on 32 and 64bit systems
$_or_24 = ord($data[$pos + 3]);
if ($_or_24 >= 128) {
// negative number
$_ord_24 = -abs((256 - $_or_24) << 24);
} else {
$_ord_24 = ($_or_24 & 127) << 24;
}
View on GitHub (pinned to 65b080eef4)
Solutions
- Re-obtain the workbook from the source and retry; verify integrity (checksum vs origin) if available.
- Screen uploads before parsing: non-empty, plausible size, and correct OLE magic bytes, so damaged files fail fast with your own error message.
- Catch Reader\Exception around Xls loads and map it to a user-facing 'corrupt file' response instead of a server error.
- Update PhpSpreadsheet — bounds/robustness fixes for the legacy reader are released regularly.
Example fix
// before
$spreadsheet = (new \PhpOffice\PhpSpreadsheet\Reader\Xls())->load('input.xls');
// Parameter pos=-4 is invalid.
// after
try {
$spreadsheet = (new \PhpOffice\PhpSpreadsheet\Reader\Xls())->load('input.xls');
} catch (\PhpOffice\PhpSpreadsheet\Reader\Exception $e) {
return ['error' => 'The .xls file is corrupt and cannot be read. Please re-export it.'];
} Defensive patterns
Strategy: try-catch
Validate before calling
// cheap structural pre-check for legacy workbooks:
$size = filesize($file);
$head = (string) @file_get_contents($file, false, null, 0, 512);
if ($size === 0 || !str_starts_with($head, "\xD0\xCF\x11\xE0")) {
throw new RuntimeException('Empty or non-OLE workbook');
} Try / catch
try { $spreadsheet = $reader->load($file); }
catch (\PhpOffice\PhpSpreadsheet\Reader\Exception $e) {
if (str_contains($e->getMessage(), 'is invalid.') || str_contains($e->getMessage(), 'OLE')) {
return ['error' => 'Corrupt .xls file — please re-export it.'];
}
throw $e;
} Prevention
- Validate file size and signature at upload; malformed containers should fail your own checks first.
- Map all legacy-reader exceptions to a user-facing 'corrupt file' outcome instead of HTTP 500s.
- Update PhpSpreadsheet regularly — the legacy Xls reader receives ongoing robustness fixes.
When it happens
Trigger: During Reader\Xls loading: constants like NUM_BIG_BLOCK_DEPOT_BLOCKS_POS or ROOT_START_BLOCK_POS combine with sizes/pointers from a damaged header so that a computed position goes negative, and getInt4d's `if ($pos < 0)` guard fires. Only reachable with malformed input — well-formed .xls files never produce negative positions.
Common situations: Truncated or bit-flipped .xls uploads; files patched by broken conversion tools; fuzzing payloads aimed at the binary reader.
Related errors
- Only Little-Endian encoding is supported.
- Unable to open stream $path
- Unsupported PPS type
- Expecting 8 byte string
- Detected loop while iterating blocks
AI-assisted analysis of PHPOffice/PhpSpreadsheet@65b080eef4 (2026-08-17).
Data as JSON: /api/errors/b755f14ee777b73b.
Report an issue: GitHub.