From 04d41d7c9f435552196868e28bfe8e22ce836fe1 Mon Sep 17 00:00:00 2001 From: Adrien Loison Date: Thu, 28 May 2015 17:59:30 -0700 Subject: [PATCH] Support XLSX that don't have a sharedStrings.xml file --- .../Helper/XLSX/SharedStringsHelper.php | 18 +++++++++++++++ src/Spout/Reader/XLSX.php | 21 +++++------------- tests/Spout/Reader/XLSXTest.php | 14 ++++++++++++ .../sheet_with_no_shared_strings_file.xlsx | Bin 0 -> 27377 bytes 4 files changed, 38 insertions(+), 15 deletions(-) create mode 100644 tests/resources/xlsx/sheet_with_no_shared_strings_file.xlsx diff --git a/src/Spout/Reader/Helper/XLSX/SharedStringsHelper.php b/src/Spout/Reader/Helper/XLSX/SharedStringsHelper.php index 678baa6..ab33725 100644 --- a/src/Spout/Reader/Helper/XLSX/SharedStringsHelper.php +++ b/src/Spout/Reader/Helper/XLSX/SharedStringsHelper.php @@ -71,6 +71,24 @@ class SharedStringsHelper $this->tempFolder = $this->fileSystemHelper->createFolder($rootTempFolder, uniqid('sharedstrings')); } + /** + * Returns whether the XLSX file contains a shared strings XML file + * + * @return bool + */ + public function hasSharedStrings() + { + $hasSharedStrings = false; + $zip = new \ZipArchive(); + + if ($zip->open($this->filePath) === true) { + $hasSharedStrings = ($zip->locateName(self::SHARED_STRINGS_XML_FILE_PATH) !== false); + $zip->close(); + } + + return $hasSharedStrings; + } + /** * Builds an in-memory array containing all the shared strings of the worksheet. * All the strings are stored in a XML file, located at 'xl/sharedStrings.xml'. diff --git a/src/Spout/Reader/XLSX.php b/src/Spout/Reader/XLSX.php index a95be81..b0a66d1 100644 --- a/src/Spout/Reader/XLSX.php +++ b/src/Spout/Reader/XLSX.php @@ -72,8 +72,12 @@ class XLSX extends AbstractReader $this->zip = new \ZipArchive(); if ($this->zip->open($filePath) === true) { - // Extracts all the strings from the worksheets for easy access in the future - $this->extractSharedStrings($filePath); + $this->sharedStringsHelper = new SharedStringsHelper($filePath, $this->tempFolder); + + if ($this->sharedStringsHelper->hasSharedStrings()) { + // Extracts all the strings from the worksheets for easy access in the future + $this->sharedStringsHelper->extractSharedStrings(); + } // Fetch all available worksheets $this->worksheetHelper = new WorksheetHelper($filePath, $this->globalFunctionsHelper); @@ -87,19 +91,6 @@ class XLSX extends AbstractReader } } - /** - * Builds an in-memory array containing all the shared strings of the worksheets. - * - * @param string $filePath Path of the XLSX file to be read - * @return void - * @throws \Box\Spout\Common\Exception\IOException If sharedStrings XML file can't be read - */ - protected function extractSharedStrings($filePath) - { - $this->sharedStringsHelper = new SharedStringsHelper($filePath, $this->tempFolder); - $this->sharedStringsHelper->extractSharedStrings(); - } - /** * Returns whether another worksheet exists after the current worksheet. * diff --git a/tests/Spout/Reader/XLSXTest.php b/tests/Spout/Reader/XLSXTest.php index 1b4a47c..9a214f2 100644 --- a/tests/Spout/Reader/XLSXTest.php +++ b/tests/Spout/Reader/XLSXTest.php @@ -100,6 +100,20 @@ class XLSXTest extends \PHPUnit_Framework_TestCase } } + /** + * @return void + */ + public function testReadShouldSupportFilesWithoutSharedStringsFile() + { + $allRows = $this->getAllRowsForFile('sheet_with_no_shared_strings_file.xlsx'); + + $expectedRows = [ + [10, 11], + [20, 21], + ]; + $this->assertEquals($expectedRows, $allRows); + } + /** * @return void */ diff --git a/tests/resources/xlsx/sheet_with_no_shared_strings_file.xlsx b/tests/resources/xlsx/sheet_with_no_shared_strings_file.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..7870631d948f06ee283415a55a97cf00ab9bcb37 GIT binary patch literal 27377 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