{"record":{"id":"e2ae35d63d72a4b7","repo":"PHPOffice/PhpSpreadsheet","slug":"unserialize-not-permitted","errorCode":null,"errorMessage":"Unserialize not permitted","messagePattern":"Unserialize not permitted","errorType":"exception","errorClass":"PhpOffice\\PhpSpreadsheet\\Exception","httpStatus":null,"severity":"error","filePath":"src/PhpSpreadsheet/Shared/XMLWriter.php","lineNumber":80,"sourceCode":"        if ($this->tempFileName != '') {\n            @unlink($this->tempFileName);\n        }\n    }\n\n    /**\n     * Unserialization is not allowed. This needs to be enforced\n     * in the class before Php8.6, but, with that release,\n     * this method is no longer needed and will not be executed.\n     *\n     * @see https://github.com/php/php-src/pull/21694\n     *\n     * @param mixed[] $data\n     */\n    public function __unserialize(array $data): void\n    {\n        $this->tempFileName = '';\n\n        throw new SpreadsheetException('Unserialize not permitted');\n    }\n\n    /**\n     * Get written data.\n     */\n    public function getData(): string\n    {\n        if ($this->tempFileName == '') {\n            return $this->outputMemory(true);\n        }\n        $this->flush();\n\n        return file_get_contents($this->tempFileName) ?: '';\n    }\n\n    /**\n     * Wrapper method for writeRaw.\n     *","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/PHPOffice/PhpSpreadsheet/blob/65b080eef4d9fd11a5796135ab145883e5c3d6a6/src/PhpSpreadsheet/Shared/XMLWriter.php#L62-L98","documentation":"PhpSpreadsheet's Shared\\XMLWriter can buffer its output into a temporary file whose handle cannot survive PHP serialization. To prevent a resurrected writer with a dangling/missing temp file, __unserialize() deliberately throws. It is a hard guard: there is no supported way to unserialize an XMLWriter instance (the method is planned to disappear once PHP 8.6 makes unserialization of internal classes impossible).","triggerScenarios":"Calling unserialize() on a byte string that contains a serialized PhpOffice\\PhpSpreadsheet\\Shared\\XMLWriter (directly or nested inside another object); caching serialized PhpSpreadsheet objects (Worksheet/Writer/Reader internals hold XMLWriter instances) in Redis, sessions, queues, or message payloads; generic deep-clone helpers implemented via serialize()/unserialize().","commonSituations":"Queues (Laravel, Symfony Messenger) that serialize job payloads carrying a Spreadsheet or a Writer; session or cache drivers that serialize whole objects; upgrading from a workflow that stored half-built export objects. The error surfaces at unserialize time, far from where the object was stored.","solutions":["Do not serialize/unserialize PhpSpreadsheet objects; store the finished artifact instead (the written XLSX/CSV file path, or the XML string from XMLWriter::getData()).","Remove Spreadsheet/Writer/XMLWriter instances from the data you pass to serialize()/cache/queue payloads before they get persisted.","If you only need the writer's output, cache getData() (the XML string) and rebuild a fresh XMLWriter when needed.","If a third-party serializer hits it, wrap the payload in a serializable DTO that excludes the writer (e.g. implement __sleep/__serialize on your wrapper to strip it)."],"exampleFix":"// before\n$blob = unserialize($redis->get('writer'));\n// throws: Unserialize not permitted\n\n// after\n$xml = $redis->get('writer-output'); // cache the string from ->getData()\n$writer = new \\PhpOffice\\PhpSpreadsheet\\Shared\\XMLWriter();\n$writer->writeRaw($xml);","handlingStrategy":"validation","validationCode":"// Never feed PhpSpreadsheet objects to unserialize(); inspect payloads before unserializing\nfunction payloadIsSafeToUnserialize(string $blob): bool\n{\n    return !str_contains($blob, 'PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\XMLWriter');\n}","typeGuard":"function isSafeForSerialization(mixed $value): bool\n{\n    return !($value instanceof \\PhpOffice\\PhpSpreadsheet\\Shared\\XMLWriter)\n        && !($value instanceof \\PhpOffice\\PhpSpreadsheet\\Spreadsheet);\n}","tryCatchPattern":"try {\n    $obj = unserialize($blob);\n} catch (\\PhpOffice\\PhpSpreadsheet\\Exception $e) {\n    // rebuild from source data instead of the cached object\n    $obj = buildFreshFromSource();\n}","preventionTips":["Cache serialized output (strings/paths), never PhpSpreadsheet objects.","Keep Spreadsheet/Writer instances out of queue payloads and sessions.","Audit deep-clone helpers that use serialize()/unserialize()."],"tags":["serialization","unserialize","xml-writer","phpspreadsheet","caching"],"backgroundTag":"unserialize-not-allowed","analyzedSha":"65b080eef4d9fd11a5796135ab145883e5c3d6a6","analyzedAt":"2026-08-17T05:40:41.646Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}