{"record":{"id":"dc46d9d172dd7616","repo":"PHPOffice/PhpSpreadsheet","slug":"can-t-open-file-filename","errorCode":null,"errorMessage":"Can't open file $filename","messagePattern":"Can't open file \\$filename","errorType":"exception","errorClass":"PhpOffice\\PhpSpreadsheet\\Reader\\Exception","httpStatus":null,"severity":"error","filePath":"src/PhpSpreadsheet/Shared/OLE.php","lineNumber":115,"sourceCode":"    public int $smallBlockSize;\n\n    /**\n     * Threshold for big blocks.\n     */\n    public int $bigBlockThreshold;\n\n    /**\n     * Reads an OLE container from the contents of the file given.\n     *\n     * @acces public\n     *\n     * @return bool true on success, PEAR_Error on failure\n     */\n    public function read(string $filename): bool\n    {\n        $fh = @fopen($filename, 'rb');\n        if ($fh === false) {\n            throw new ReaderException(\"Can't open file $filename\");\n        }\n        $this->_file_handle = $fh;\n\n        $signature = fread($fh, 8);\n        if (\"\\xD0\\xCF\\x11\\xE0\\xA1\\xB1\\x1A\\xE1\" != $signature) {\n            throw new ReaderException(\"File doesn't seem to be an OLE container.\");\n        }\n        fseek($fh, 28);\n        if (fread($fh, 2) != \"\\xFE\\xFF\") {\n            // This shouldn't be a problem in practice\n            throw new ReaderException('Only Little-Endian encoding is supported.');\n        }\n        // Size of blocks and short blocks in bytes\n        /** @var int<1, max> */\n        $temp = 2 ** self::readInt2($fh);\n        $this->bigBlockSize = $temp;\n        $this->smallBlockSize = 2 ** self::readInt2($fh);\n","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/PHPOffice/PhpSpreadsheet/blob/65b080eef4d9fd11a5796135ab145883e5c3d6a6/src/PhpSpreadsheet/Shared/OLE.php#L97-L133","documentation":"Thrown by Shared\\OLE::read() when fopen() on the given path fails, before any OLE parsing starts. It means PHP could not open the file in binary read mode at all — the OLE (.xls container) layer never saw the content. Suppressed error handling (@fopen) makes the exception the only signal of the underlying I/O problem.","triggerScenarios":"Calling $ole->read($filename) (directly or via a reader that uses the PEAR-style OLE class) with a path that does not exist, is not readable by the PHP user, is a directory, or uses a stream wrapper that is disallowed/unregistered. File::assertFile() style checks happen in some callers but read() itself only does the fopen.","commonSituations":"Reading an uploaded file after it was moved/deleted (tmp_name reused across requests); permission mismatch under FPM when the file was created by CLI/cron; path typos or wrong relative CWD in queue workers; safe-mode-style wrapper restrictions on remote URLs.","solutions":["Verify the file exists and is readable before parsing: is_file($filename) && is_readable($filename), and log the absolute path via realpath() at the failure site.","Fix permissions/ownership so the web-server or worker user can read the file (chmod 644 / correct group).","If the path is user-supplied, resolve it once with realpath() at request start and keep that absolute path for the read.","For uploads, move the file to your own storage (move_uploaded_file) and read from there, never from the raw tmp path twice."],"exampleFix":"// before\n$ole->read($path); // Can't open file /tmp/tmpXyz/report.xls\n\n// after\nif (!is_string($path) || !is_file($path) || !is_readable($path)) {\n    throw new InvalidArgumentException(\"Excel file missing or unreadable: $path\");\n}\n$ole->read($path);","handlingStrategy":"validation","validationCode":"if (!is_string($file) || !is_file($file) || !is_readable($file)) {\n    throw new InvalidArgumentException(\"Excel file missing or unreadable: \" . var_export($file, true));\n}\n$ole->read($file);","typeGuard":"function readableExcelFile(string $file): ?string\n{\n    return (is_file($file) && is_readable($file)) ? realpath($file) : null;\n}","tryCatchPattern":"try { $ole->read($file); }\ncatch (\\PhpOffice\\PhpSpreadsheet\\Reader\\Exception $e) {\n    if (str_starts_with($e->getMessage(), \"Can't open file\")) {\n        // missing/unreadable — fix the path or permissions, do not retry blindly\n        throw new RuntimeException(\"Cannot read workbook at $file\", 0, $e);\n    }\n    throw $e;\n}","preventionTips":["Resolve user-supplied paths once with realpath() and reuse the absolute path.","Move uploads into your own storage before parsing; never re-read a tmp path on a later request.","Check ownership/permissions for the PHP-FPM user when files are produced by CLI/cron jobs."],"tags":["file-io","permissions","file-not-found","ole","phpspreadsheet"],"backgroundTag":"file-not-readable","analyzedSha":"65b080eef4d9fd11a5796135ab145883e5c3d6a6","analyzedAt":"2026-08-17T05:40:41.646Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}