From 2952cf5526959b47abf9ccd953fa9fc093a276d3 Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Thu, 18 Jul 2024 13:30:58 -0700 Subject: [PATCH] Ods Reader Allow Omission of Some Page Settings Tags Fix #4099. Ods Reader was expecting there to always be `header-style` and `footer-style` tags when `page-layout` tag is present, but these need not exist. It seemed like there might be other exposures along this line in `readPageSettingStyles`; rather than waiting for a problem report to show up for each, the code is updated to use `->item(0)` in place of `[0]` when appropriate, and make use of the nullsafe `?->` operator introduced with Php8. --- .../Reader/Ods/PageSettings.php | 30 +++++++++--------- .../Reader/Ods/Issue4099Test.php | 28 ++++++++++++++++ tests/data/Reader/Ods/issue.4099.ods | Bin 0 -> 8887 bytes 3 files changed, 43 insertions(+), 15 deletions(-) create mode 100644 tests/PhpSpreadsheetTests/Reader/Ods/Issue4099Test.php create mode 100644 tests/data/Reader/Ods/issue.4099.ods diff --git a/src/PhpSpreadsheet/Reader/Ods/PageSettings.php b/src/PhpSpreadsheet/Reader/Ods/PageSettings.php index f3e956c91..fd35de5b9 100644 --- a/src/PhpSpreadsheet/Reader/Ods/PageSettings.php +++ b/src/PhpSpreadsheet/Reader/Ods/PageSettings.php @@ -55,22 +55,22 @@ class PageSettings foreach ($styles as $styleSet) { $styleName = $styleSet->getAttributeNS($this->stylesNs, 'name'); - $pageLayoutProperties = $styleSet->getElementsByTagNameNS($this->stylesNs, 'page-layout-properties')[0]; - $styleOrientation = $pageLayoutProperties->getAttributeNS($this->stylesNs, 'print-orientation'); - $styleScale = $pageLayoutProperties->getAttributeNS($this->stylesNs, 'scale-to'); - $stylePrintOrder = $pageLayoutProperties->getAttributeNS($this->stylesNs, 'print-page-order'); - $centered = $pageLayoutProperties->getAttributeNS($this->stylesNs, 'table-centering'); + $pageLayoutProperties = $styleSet->getElementsByTagNameNS($this->stylesNs, 'page-layout-properties')->item(0); + $styleOrientation = $pageLayoutProperties?->getAttributeNS($this->stylesNs, 'print-orientation'); + $styleScale = $pageLayoutProperties?->getAttributeNS($this->stylesNs, 'scale-to'); + $stylePrintOrder = $pageLayoutProperties?->getAttributeNS($this->stylesNs, 'print-page-order'); + $centered = $pageLayoutProperties?->getAttributeNS($this->stylesNs, 'table-centering'); - $marginLeft = $pageLayoutProperties->getAttributeNS($this->stylesFo, 'margin-left'); - $marginRight = $pageLayoutProperties->getAttributeNS($this->stylesFo, 'margin-right'); - $marginTop = $pageLayoutProperties->getAttributeNS($this->stylesFo, 'margin-top'); - $marginBottom = $pageLayoutProperties->getAttributeNS($this->stylesFo, 'margin-bottom'); - $header = $styleSet->getElementsByTagNameNS($this->stylesNs, 'header-style')[0]; - $headerProperties = $header->getElementsByTagNameNS($this->stylesNs, 'header-footer-properties')[0]; - $marginHeader = isset($headerProperties) ? $headerProperties->getAttributeNS($this->stylesFo, 'min-height') : null; - $footer = $styleSet->getElementsByTagNameNS($this->stylesNs, 'footer-style')[0]; - $footerProperties = $footer->getElementsByTagNameNS($this->stylesNs, 'header-footer-properties')[0]; - $marginFooter = isset($footerProperties) ? $footerProperties->getAttributeNS($this->stylesFo, 'min-height') : null; + $marginLeft = $pageLayoutProperties?->getAttributeNS($this->stylesFo, 'margin-left'); + $marginRight = $pageLayoutProperties?->getAttributeNS($this->stylesFo, 'margin-right'); + $marginTop = $pageLayoutProperties?->getAttributeNS($this->stylesFo, 'margin-top'); + $marginBottom = $pageLayoutProperties?->getAttributeNS($this->stylesFo, 'margin-bottom'); + $header = $styleSet->getElementsByTagNameNS($this->stylesNs, 'header-style')->item(0); + $headerProperties = $header?->getElementsByTagNameNS($this->stylesNs, 'header-footer-properties')?->item(0); + $marginHeader = $headerProperties?->getAttributeNS($this->stylesFo, 'min-height'); + $footer = $styleSet->getElementsByTagNameNS($this->stylesNs, 'footer-style')->item(0); + $footerProperties = $footer?->getElementsByTagNameNS($this->stylesNs, 'header-footer-properties')?->item(0); + $marginFooter = $footerProperties?->getAttributeNS($this->stylesFo, 'min-height'); $this->pageLayoutStyles[$styleName] = (object) [ 'orientation' => $styleOrientation ?: PageSetup::ORIENTATION_DEFAULT, diff --git a/tests/PhpSpreadsheetTests/Reader/Ods/Issue4099Test.php b/tests/PhpSpreadsheetTests/Reader/Ods/Issue4099Test.php new file mode 100644 index 000000000..2b38181a6 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Reader/Ods/Issue4099Test.php @@ -0,0 +1,28 @@ +file . '#styles.xml'; + $contents = (string) file_get_contents($zipFile); + self::assertStringContainsString('page-layout ', $contents); + self::assertStringNotContainsString('header-style', $contents); + self::assertStringNotContainsString('footer-style', $contents); + $reader = new OdsReader(); + $spreadsheet = $reader->load($this->file); + $sheet = $spreadsheet->getActiveSheet(); + self::assertSame('FirstCell', $sheet->getCell('A1')->getValue()); + $spreadsheet->disconnectWorksheets(); + } +} diff --git a/tests/data/Reader/Ods/issue.4099.ods b/tests/data/Reader/Ods/issue.4099.ods new file mode 100644 index 0000000000000000000000000000000000000000..26b17ecbd3f1b1ef4331515747f54d667161c5b5 GIT binary patch literal 8887 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 literal 0 HcmV?d00001