From ef1d6b63e7c49e1a26591f82112371a24125fb89 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Tue, 2 Jul 2024 14:53:39 +0200 Subject: [PATCH] Fix sheet reference (#16) fix https://github.com/alexandrainst/php-xlsx-fast-editor/issues/15 Fix `XlsxFastEditor::getWorksheetNumber()` which was not returning the proper number in case of workbooks in which sheets have been reordered or removed. --- phpstan.neon | 2 ++ src/XlsxFastEditor.php | 24 ++++++++++++++++++++---- tests/test.php | 5 ++--- tests/test.xlsx | Bin 14951 -> 15048 bytes 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/phpstan.neon b/phpstan.neon index 2368b26..15def8e 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -27,5 +27,7 @@ parameters: missingCheckedExceptionInThrows: true tooWideThrowType: true implicitThrows: false + ignoreErrors: + - '#Only booleans are allowed in (a negated boolean|a ternary operator condition|an elseif condition|an if condition|&&|\|\|), (bool|false|int(<[0-9, max]+>)?|true|null|\|)+ given.*#' includes: - vendor/phpstan/phpstan-strict-rules/rules.neon diff --git a/src/XlsxFastEditor.php b/src/XlsxFastEditor.php index d5fcf67..d27ed50 100644 --- a/src/XlsxFastEditor.php +++ b/src/XlsxFastEditor.php @@ -27,6 +27,7 @@ final class XlsxFastEditor private const CALC_CHAIN_CACHE_PATH = 'xl/calcChain.xml'; private const SHARED_STRINGS_PATH = 'xl/sharedStrings.xml'; private const WORKBOOK_PATH = 'xl/workbook.xml'; + private const WORKBOOK_RELS_PATH = 'xl/_rels/workbook.xml.rels'; private \ZipArchive $zip; @@ -280,9 +281,24 @@ public function getWorksheetCount(): int public function getWorksheetNumber(string $sheetName): int { $xpath = $this->getXPathFromPath(self::WORKBOOK_PATH); - $sheetId = $xpath->evaluate("normalize-space(/o:workbook/o:sheets/o:sheet[@name='$sheetName'][1]/@sheetId)"); - if (is_string($sheetId)) { - return (int)$sheetId; + $xpath->registerNamespace('r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'); + $rId = $xpath->evaluate("normalize-space(/o:workbook/o:sheets/o:sheet[@name='$sheetName'][1]/@r:id)"); + if (!is_string($rId) || $rId === '') { + return -1; + } + + try { + $xpath = $this->getXPathFromPath(self::WORKBOOK_RELS_PATH); + $xpath->registerNamespace('pr', 'http://schemas.openxmlformats.org/package/2006/relationships'); + $target = $xpath->evaluate("normalize-space(/pr:Relationships/pr:Relationship[@Id='$rId'][1]/@Target)"); + if (is_string($target) && preg_match('/(\d+)/i', $target, $matches)) { + return (int)$matches[1]; + } + } catch (XlsxFastEditorFileFormatException $ex) { // phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch + } + + if (preg_match('/(\d+)/i', $rId, $matches)) { + return (int)$matches[1]; } return -1; } @@ -297,7 +313,7 @@ public function getWorksheetNumber(string $sheetName): int public function getWorksheetName(int $sheetNumber): ?string { $xpath = $this->getXPathFromPath(self::WORKBOOK_PATH); - $sheetName = $xpath->evaluate("normalize-space(/o:workbook/o:sheets/o:sheet[$sheetNumber][1]/@name)"); + $sheetName = $xpath->evaluate("normalize-space(/o:workbook/o:sheets/o:sheet[$sheetNumber]/@name)"); return is_string($sheetName) ? $sheetName : null; } diff --git a/tests/test.php b/tests/test.php index 230c44f..a6eef8c 100644 --- a/tests/test.php +++ b/tests/test.php @@ -26,7 +26,7 @@ assert(XlsxFastEditor::excelDateToDateTime(44865, 1904)->format('c') === '2026-11-01T00:00:00+00:00'); $sheet1 = $xlsxFastEditor->getWorksheetNumber('Sheet1'); - assert($sheet1 === 1); + assert($sheet1 === 3); assert($xlsxFastEditor->deleteRow($sheet1, 5) === true); @@ -42,7 +42,6 @@ assert($xlsxFastEditor->readHyperlink($sheet1, 'C3') === null); $sheet2 = $xlsxFastEditor->getWorksheetNumber('Sheet2'); - assert($sheet2 === 2); assert($xlsxFastEditor->getWorksheetName($sheet2) === 'Sheet2'); assert($xlsxFastEditor->readFormula($sheet2, 'c2') === '=Sheet1!C2*2'); @@ -66,7 +65,7 @@ assert($xlsxFastEditor->getLastRow($sheet1)?->number() === 4); $sheet3 = $xlsxFastEditor->getWorksheetNumber('Sheet3'); - assert($sheet3 === 3); + assert($xlsxFastEditor->getWorksheetName($sheet3) === 'Sheet3'); assert($xlsxFastEditor->getHighestColumnName($sheet3) === 'G'); $row4 = $xlsxFastEditor->getRow($sheet1, 4); diff --git a/tests/test.xlsx b/tests/test.xlsx index 3e9377086e1c3d737e987467d69e845f425cc783..9abd9b64afa956efa23bac9f994e7d97c1458ca5 100644 GIT binary patch delta 6975 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