diff --git a/src/PhpSpreadsheet/Reader/Ods.php b/src/PhpSpreadsheet/Reader/Ods.php index 5fa253b1e..08fb4f19a 100644 --- a/src/PhpSpreadsheet/Reader/Ods.php +++ b/src/PhpSpreadsheet/Reader/Ods.php @@ -339,11 +339,7 @@ class Ods extends BaseReader // Styles $this->allStyles = $this->numberFormats = []; - $dom = new DOMDocument('1.01', 'UTF-8'); - $dom->loadXML( - $this->getSecurityScannerOrThrow() - ->scan($zip->getFromName('styles.xml')) - ); + $dom = $this->loadDom('styles.xml', $zip); $officeNs = (string) $dom->lookupNamespaceUri('office'); $styleNs = (string) $dom->lookupNamespaceUri('style'); $fontNs = (string) $dom->lookupNamespaceUri('fo'); @@ -409,11 +405,7 @@ class Ods extends BaseReader // Main Content - $dom = new DOMDocument('1.01', 'UTF-8'); - $dom->loadXML( - $this->getSecurityScannerOrThrow() - ->scan($zip->getFromName(self::INITIAL_FILE)) - ); + $dom = $this->loadDom(self::INITIAL_FILE, $zip); $pageSettings->readStyleCrossReferences($dom); @@ -1428,11 +1420,7 @@ class Ods extends BaseReader private function processSettings(ZipArchive $zip, Spreadsheet $spreadsheet): void { - $dom = new DOMDocument('1.01', 'UTF-8'); - $dom->loadXML( - $this->getSecurityScannerOrThrow() - ->scan($zip->getFromName('settings.xml')) - ); + $dom = $this->loadDom('settings.xml', $zip); $configNs = (string) $dom->lookupNamespaceUri('config'); $officeNs = (string) $dom->lookupNamespaceUri('office'); $settings = $dom->getElementsByTagNameNS($officeNs, 'settings') @@ -1869,4 +1857,31 @@ class Ods extends BaseReader } } } + + private function loadDom(string $file, ZipArchive $zip): DOMDocument + { + $dom = new DOMDocument('1.01', 'UTF-8'); + $orig = false; + + try { + $orig = libxml_use_internal_errors(true); + $result = $dom->loadXML( + $this->getSecurityScannerOrThrow() + ->scan($zip->getFromName($file)) + ); + if ($result === false) { + $fatal = false; + foreach (libxml_get_errors() as $err) { + if ($err->level === LIBXML_ERR_FATAL) { + throw new Exception($err->message); + } + } + } + } finally { + libxml_clear_errors(); + libxml_use_internal_errors($orig); + } + + return $dom; + } } diff --git a/tests/PhpSpreadsheetTests/Reader/Ods/BadXmlTest.php b/tests/PhpSpreadsheetTests/Reader/Ods/BadXmlTest.php new file mode 100644 index 000000000..0964d733b --- /dev/null +++ b/tests/PhpSpreadsheetTests/Reader/Ods/BadXmlTest.php @@ -0,0 +1,41 @@ +expectException(ReaderException::class); + $this->expectExceptionMessage('Opening and ending tag mismatch'); + $fileName = self::DIRECTORY . 'badstyle.ods'; + $reader = new OdsReader(); + $reader->load($fileName); + } + + public function testBadContent(): void + { + $this->expectException(ReaderException::class); + $this->expectExceptionMessage('Opening and ending tag mismatch'); + $fileName = self::DIRECTORY . 'badcontent.ods'; + $reader = new OdsReader(); + $reader->load($fileName); + } + + public function testBadSettings(): void + { + $this->expectException(ReaderException::class); + $this->expectExceptionMessage('Premature end of data'); + $fileName = self::DIRECTORY . 'badsettings.ods'; + $reader = new OdsReader(); + $reader->load($fileName); + } +} diff --git a/tests/data/Reader/Ods/badcontent.ods b/tests/data/Reader/Ods/badcontent.ods new file mode 100644 index 000000000..b9d4ca043 Binary files /dev/null and b/tests/data/Reader/Ods/badcontent.ods differ diff --git a/tests/data/Reader/Ods/badsettings.ods b/tests/data/Reader/Ods/badsettings.ods new file mode 100644 index 000000000..1de2e0aff Binary files /dev/null and b/tests/data/Reader/Ods/badsettings.ods differ diff --git a/tests/data/Reader/Ods/badstyle.ods b/tests/data/Reader/Ods/badstyle.ods new file mode 100644 index 000000000..0a3ca847d Binary files /dev/null and b/tests/data/Reader/Ods/badstyle.ods differ