{"record":{"id":"a5819cfc6771d833","repo":"PHPOffice/PHPWord","slug":"the-filename-sfilename-is-not-recognised-as-an-ole-file","errorCode":null,"errorMessage":"The filename ' . $sFileName . ' is not recognised as an OLE file","messagePattern":"The filename ' \\. \\$sFileName \\. ' is not recognised as an OLE file","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/PhpWord/Shared/OLERead.php","lineNumber":96,"sourceCode":"     *\n     * @param $sFileName string Filename\n     *\n     * @throws Exception\n     */\n    public function read($sFileName)\n    {\n        // Check if file exists and is readable\n        if (!is_readable($sFileName)) {\n            throw new Exception('Could not open ' . $sFileName . ' for reading! File does not exist, or it is not readable.');\n        }\n\n        // Get the file identifier\n        // Don't bother reading the whole file until we know it's a valid OLE file\n        $this->data = file_get_contents($sFileName, false, null, 0, 8);\n\n        // Check OLE identifier\n        if ($this->data != self::IDENTIFIER_OLE) {\n            throw new Exception('The filename ' . $sFileName . ' is not recognised as an OLE file');\n        }\n\n        // Get the file data\n        $this->data = file_get_contents($sFileName);\n\n        // Total number of sectors used for the SAT\n        $this->numBigBlockDepotBlocks = self::getInt4d($this->data, self::NUM_BIG_BLOCK_DEPOT_BLOCKS_POS);\n\n        // SecID of the first sector of the directory stream\n        $this->rootStartBlock = self::getInt4d($this->data, self::ROOT_START_BLOCK_POS);\n\n        // SecID of the first sector of the SSAT (or -2 if not extant)\n        $this->sbdStartBlock = self::getInt4d($this->data, self::SMALL_BLOCK_DEPOT_BLOCK_POS);\n\n        // SecID of the first sector of the MSAT (or -2 if no additional sectors are used)\n        $this->extensionBlock = self::getInt4d($this->data, self::EXTENSION_BLOCK_POS);\n\n        // Total number of sectors used by MSAT","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/PHPOffice/PHPWord/blob/aef95c04151b5633cc505f672ddd6a71da900ee1/src/PhpWord/Shared/OLERead.php#L78-L114","documentation":"OLERead::read() reads the first 8 bytes of the file and compares them to the OLE magic identifier (D0 CF 11 E0 A1 B1 1A E1). If they differ, the file exists and is readable but is not an OLE compound document, so Exception is thrown. This is how the library rejects non-OLE files passed to legacy readers.","triggerScenarios":"Loading a file that exists and is readable but whose header is not the OLE signature: a .docx (ZIP) passed to a legacy .doc reader, a renamed text/HTML file with a .doc extension, an RTF file, or a truncated/corrupted OLE file whose first 8 bytes were overwritten.","commonSituations":"Users renaming .docx or .rtf files to .doc; script/autoresponse attachments saved truncated; confusing the legacy Doc reader with the Word2007 reader; partial uploads.","solutions":["Verify the file type by its real content, not extension (e.g. `file` command or finfo) before choosing a reader.","Use the Word2007 reader for .docx (zip) files instead of the legacy OLE-based reader.","Re-obtain the original file if it is truncated or corrupted (check file size / re-upload).","Optionally check the first 8 bytes yourself: substr($data,0,8) === \"\\xD0\\xCF\\x11\\xE0\\xA1\\xB1\\x1A\\xE1\"."],"exampleFix":"// before\n$phpWord = \\PhpOffice\\PhpWord\\IOFactory::load('report.doc'); // actually a docx\n// after\n$finfo = new finfo(FILEINFO_MIME_TYPE);\n$mime = $finfo->file('report.doc');\n$phpWord = str_contains($mime, 'zip')\n    ? \\PhpOffice\\PhpWord\\IOFactory::createReader('Word2007')->load('report.doc')\n    : \\PhpOffice\\PhpWord\\IOFactory::load('report.doc');","handlingStrategy":"validation","validationCode":"$magic = (string) file_get_contents($path, false, null, 0, 8);\n$isOle = $magic === \"\\xD0\\xCF\\x11\\xE0\\xA1\\xB1\\x1A\\xE1\";\n$isZip = str_starts_with($magic, \"PK\\x03\\x04\");\nif (!$isOle && !$isZip) {\n    throw new InvalidArgumentException(\"Unrecognized document format: $path\");\n}\n$phpWord = $isZip\n    ? IOFactory::createReader('Word2007')->load($path)\n    : IOFactory::load($path);","typeGuard":null,"tryCatchPattern":"try {\n    $phpWord = IOFactory::load($path);\n} catch (\\PhpOffice\\PhpWord\\Exception\\Exception $e) {\n    if (str_contains($e->getMessage(), 'not recognised as an OLE file')) {\n        throw new RuntimeException(\"Not a valid legacy .doc file: $path\", 0, $e);\n    }\n    throw $e;\n}","preventionTips":["Detect file type by content (finfo/magic bytes), never by extension","Route .docx (zip) files to the Word2007 reader, not the OLE-based one","Validate uploads (size + magic bytes) at ingestion time","Reject truncated files by comparing to expected sizes/checksums"],"tags":["phpword","ole","file-format","corrupt-file"],"backgroundTag":"unsupported-file-format","analyzedSha":"aef95c04151b5633cc505f672ddd6a71da900ee1","analyzedAt":"2026-09-14T10:53:58.933Z","contentChangedAt":"2026-09-14T10:53:58.933Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}