{"record":{"id":"746a1d0b77c6acbd","repo":"PHPOffice/PhpSpreadsheet","slug":"file-appears-to-be-corrupt","errorCode":null,"errorMessage":"File appears to be corrupt","messagePattern":"File appears to be corrupt","errorType":"exception","errorClass":"PhpOffice\\PhpSpreadsheet\\Exception","httpStatus":null,"severity":"error","filePath":"src/PhpSpreadsheet/Reader/XlsBase.php","lineNumber":374,"sourceCode":"        for ($i = 0; $i < $strLen; ++$i) {\n            $uncompressedString .= $string[$i] . \"\\0\";\n        }\n\n        return $uncompressedString;\n    }\n\n    /**\n     * Convert string to UTF-8. Only used for BIFF5.\n     */\n    protected function decodeCodepage(string $string): string\n    {\n        return StringHelper::convertEncoding($string, 'UTF-8', $this->codepage);\n    }\n\n    protected static function confirmPos(string $data, int $pos): void\n    {\n        if ($pos >= strlen($data)) {\n            throw new PhpSpreadsheetException('File appears to be corrupt'); // @codeCoverageIgnore\n        }\n    }\n\n    /**\n     * Read 16-bit unsigned integer.\n     */\n    public static function getUInt2d(string $data, int $pos): int\n    {\n        self::confirmPos($data, $pos + 1);\n\n        return ord($data[$pos]) | (ord($data[$pos + 1]) << 8);\n    }\n\n    /**\n     * Read 16-bit signed integer.\n     */\n    public static function getInt2d(string $data, int $pos): int\n    {","sourceCodeStart":356,"sourceCodeEnd":392,"githubUrl":"https://github.com/PHPOffice/PhpSpreadsheet/blob/65b080eef4d9fd11a5796135ab145883e5c3d6a6/src/PhpSpreadsheet/Reader/XlsBase.php#L356-L392","documentation":"getUInt2d() reads two bytes at a position confirmed against the data length; when the position is at/past the end of the loaded byte stream, confirmPos() throws 'File appears to be corrupt'. In practice the data ended earlier than the record structure promised.","triggerScenarios":"A truncated .xls (interrupted upload/download, disk-full during write, partial archive extraction) where the reader walks records past EOF; files whose OLE workbook stream was cut short.","commonSituations":"User uploads cut off by PHP upload limits or proxy timeouts; files copied from failing media; spreadsheets embedded in PDFs/documents extracted incompletely.","solutions":["Verify the transfer end-to-end: compare file size/checksum with the source and re-download","Confirm the file opens in Excel; if Excel also complains, it is genuinely truncated","Extract a fresh copy from the original archive or re-export from the source system","Raise/verify upload_max_filesize and post_max_size and check for proxy limits if it came from HTTP upload"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if (!is_file($path) || filesize($path) === 0 || filesize($path) < 512) {\n    throw new InvalidArgumentException('File missing, empty, or truncated: ' . $path);\n}","typeGuard":null,"tryCatchPattern":"try {\n    $spreadsheet = IOFactory::load($path);\n} catch (\\PhpOffice\\PhpSpreadsheet\\Reader\\Exception $e) {\n    if (str_contains($e->getMessage(), 'File appears to be corrupt')) {\n        // likely truncated transfer: compare checksum with source and re-download\n    }\n}","preventionTips":["Verify upload completeness (size + checksum) before parsing","Check PHP upload limits and proxy timeouts on import endpoints","Store originals immutably and re-copy when corruption is detected"],"tags":["xls","corruption","truncated-file","phpspreadsheet"],"backgroundTag":"truncated-file","analyzedSha":"65b080eef4d9fd11a5796135ab145883e5c3d6a6","analyzedAt":"2026-08-17T05:40:41.646Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}