{"record":{"id":"a8566677335a0761","repo":"PHPOffice/PhpSpreadsheet","slug":"failed-to-load-file-filename-as-a-dom-document","errorCode":null,"errorMessage":"Failed to load file {filename} as a DOM Document","messagePattern":"Failed to load file (.+?) as a DOM Document","errorType":"exception","errorClass":"PhpOffice\\PhpSpreadsheet\\Exception","httpStatus":null,"severity":"error","filePath":"src/PhpSpreadsheet/Reader/Html.php","lineNumber":823,"sourceCode":"            $useErrors = libxml_use_internal_errors($this->suppressLoadWarnings);\n        } else {\n            $useErrors = null;\n        }\n\n        try {\n            $convert = $this->getSecurityScannerOrThrow()->scanFile($filename);\n            $convert = static::replaceNonAsciiIfNeeded($convert);\n            $loaded = ($convert === null) ? false : $dom->loadHTML($convert);\n        } catch (Throwable $e) {\n            $loaded = false;\n        } finally {\n            $this->libxmlMessages = libxml_get_errors();\n            if (is_bool($useErrors)) {\n                libxml_use_internal_errors($useErrors);\n            }\n        }\n        if ($loaded === false) {\n            throw new Exception('Failed to load file ' . $filename . ' as a DOM Document', 0, $e ?? null);\n        }\n        self::loadProperties($dom, $spreadsheet);\n\n        return $this->loadDocument($dom, $spreadsheet);\n    }\n\n    private static function loadProperties(DOMDocument $dom, Spreadsheet $spreadsheet): void\n    {\n        $properties = $spreadsheet->getProperties();\n        foreach ($dom->getElementsByTagName('meta') as $meta) {\n            $metaContent = (string) $meta->getAttribute('content');\n            if ($metaContent !== '') {\n                $metaName = (string) $meta->getAttribute('name');\n                switch ($metaName) {\n                    case 'author':\n                        $properties->setCreator($metaContent);\n\n                        break;","sourceCodeStart":805,"sourceCodeEnd":841,"githubUrl":"https://github.com/PHPOffice/PhpSpreadsheet/blob/65b080eef4d9fd11a5796135ab145883e5c3d6a6/src/PhpSpreadsheet/Reader/Html.php#L805-L841","documentation":"In Html::loadIntoExisting(), the file content is first passed through the security scanner (XXE/external-entity protection), optionally transformed, then handed to DOMDocument::loadHTML(). If loadHTML returns false, or anything throwable happens along the way (including the scanner rejecting the content), the reader throws this exception with the original failure chained as getPrevious(). libxml diagnostics are captured in the reader's libxml messages for inspection.","triggerScenarios":"Grossly malformed or binary content fed as HTML; content rejected by the security scanner (DOCTYPE/external-entity patterns); scanFile/transform steps returning null; encoding breakage that makes libxml bail.","commonSituations":"Parsing untrusted or scraped HTML of unknown quality; files containing DTD/ENTITY declarations; upstream content silently changing format (JSON error pages saved as .html).","solutions":["Inspect exception->getPrevious() and the reader's captured libxml messages to find the true cause","If the scanner rejected it, strip risky constructs (DOCTYPE, ENTITY declarations) before loading","Repair the markup with ext-tidy (or a sanitizer) and retry; fall back to loadSpreadsheetFromString on cleaned content"],"exampleFix":"// before\n$spreadsheet = (new Html())->load($uploadPath); // scanner rejects DTD -> 'Failed to load file ... as a DOM Document'\n\n// after\n$clean = preg_replace('/<!DOCTYPE[^>]*>|<!ENTITY[^>]*>/i', '', (string) file_get_contents($uploadPath));\n$reader = new Html();\ntry {\n    $spreadsheet = $reader->loadSpreadsheetFromString($clean);\n} catch (Exception $e) {\n    error_log('HTML load failed: ' . (string) $e->getPrevious());\n    throw $e;\n}","handlingStrategy":"try-catch","validationCode":"$source = (string) file_get_contents($filename);\nif (preg_match('/<!DOCTYPE|<!ENTITY/i', $source) === 1) {\n    $filename = null; // flag: sanitize before loading\n    $source = preg_replace('/<!DOCTYPE[^>]*>|<!ENTITY[^>]*>/i', '', $source);\n    // load the sanitized string via loadSpreadsheetFromString instead of the file\n}","typeGuard":null,"tryCatchPattern":"try {\n    $spreadsheet = (new Html())->load($filename);\n} catch (\\PhpOffice\\PhpSpreadsheet\\Exception $e) {\n    $cause = $e->getPrevious();\n    if ($cause instanceof SecurityException || str_contains((string) $cause, 'Entity')) {\n        // security scanner rejected the markup — sanitize and retry once\n    }\n    throw $e;\n}","preventionTips":["Inspect getPrevious() and the reader's libxml messages before guessing at fixes","Sanitize untrusted HTML (strip DOCTYPE/ENTITY) ahead of loading","Clean scraped markup through tidy/sanitizers in ingestion, not at parse time"],"tags":["html","domdocument","libxml","xxe","security-scanner"],"backgroundTag":"html-parse-failure","analyzedSha":"65b080eef4d9fd11a5796135ab145883e5c3d6a6","analyzedAt":"2026-08-17T05:40:41.646Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}