diff --git a/src/Spout/Reader/Helper/XLSX/SharedStringsHelper.php b/src/Spout/Reader/Helper/XLSX/SharedStringsHelper.php index 1a73fbb..005337c 100644 --- a/src/Spout/Reader/Helper/XLSX/SharedStringsHelper.php +++ b/src/Spout/Reader/Helper/XLSX/SharedStringsHelper.php @@ -34,6 +34,9 @@ class SharedStringsHelper /** Value to use to escape the line feed character ("\n") */ const ESCAPED_LINE_FEED_CHARACTER = '_x000A_'; + /** Disabling this will increase your memory usage but can improve your execution time */ + protected $useSharedStringsFileCache; + /** @var string Path of the XLSX file being read */ protected $filePath; @@ -56,15 +59,17 @@ class SharedStringsHelper * @var string Contents of the temporary file that was last read * @see MAX_NUM_STRINGS_PER_TEMP_FILE */ - protected $inMemoryTempFileContents; - + protected $inMemoryContents; + /** * @param string $filePath Path of the XLSX file being read * @param string|void $tempFolder Temporary folder where the temporary files to store shared strings will be stored + * @param bool|void $useSharedStringsFileCache Disabling this will increase your memory usage but can improve your execution time */ - public function __construct($filePath, $tempFolder = null) + public function __construct($filePath, $tempFolder = null, $useSharedStringsFileCache = true) { $this->filePath = $filePath; + $this->useSharedStringsFileCache = $useSharedStringsFileCache; $rootTempFolder = ($tempFolder) ?: sys_get_temp_dir(); $this->fileSystemHelper = new FileSystemHelper($rootTempFolder); @@ -141,11 +146,19 @@ class SharedStringsHelper $unescapedTextValue = $escaper->unescape($textValue); - // The shared string retrieval logic expects each cell data to be on one line only - // Encoding the line feed character allows to preserve this assumption - $lineFeedEncodedTextValue = $this->escapeLineFeed($unescapedTextValue); - - $this->writeSharedStringToTempFile($lineFeedEncodedTextValue, $sharedStringIndex); + if ($this->useSharedStringsFileCache) { + // The shared string retrieval logic expects each cell data to be on one line only + // Encoding the line feed character allows to preserve this assumption + $lineFeedEncodedTextValue = $this->escapeLineFeed($unescapedTextValue); + + $this->writeSharedStringToTempFile($lineFeedEncodedTextValue, $sharedStringIndex); + } else { + if (!isset($this->inMemoryContents)) { + $this->inMemoryContents = []; + } + + $this->inMemoryContents[$sharedStringIndex] = $unescapedTextValue; + } $sharedStringIndex++; @@ -262,25 +275,32 @@ class SharedStringsHelper */ public function getStringAtIndex($sharedStringIndex) { - $tempFilePath = $this->getSharedStringTempFilePath($sharedStringIndex); - $indexInFile = $sharedStringIndex % self::MAX_NUM_STRINGS_PER_TEMP_FILE; - - if (!file_exists($tempFilePath)) { - throw new SharedStringNotFoundException("Shared string temp file not found: $tempFilePath ; for index: $sharedStringIndex"); - } - - if ($this->inMemoryTempFilePath !== $tempFilePath) { - // free memory - unset($this->inMemoryTempFileContents); - - $this->inMemoryTempFileContents = explode(PHP_EOL, file_get_contents($tempFilePath)); - $this->inMemoryTempFilePath = $tempFilePath; - } - $sharedString = null; - if (array_key_exists($indexInFile, $this->inMemoryTempFileContents)) { - $escapedSharedString = $this->inMemoryTempFileContents[$indexInFile]; - $sharedString = $this->unescapeLineFeed($escapedSharedString); + + if ($this->useSharedStringsFileCache) { + $tempFilePath = $this->getSharedStringTempFilePath($sharedStringIndex); + $indexInFile = $sharedStringIndex % self::MAX_NUM_STRINGS_PER_TEMP_FILE; + + if (!file_exists($tempFilePath)) { + throw new SharedStringNotFoundException("Shared string temp file not found: $tempFilePath ; for index: $sharedStringIndex"); + } + + if ($this->inMemoryTempFilePath !== $tempFilePath) { + // free memory + unset($this->inMemoryContents); + + $this->inMemoryContents = explode(PHP_EOL, file_get_contents($tempFilePath)); + $this->inMemoryTempFilePath = $tempFilePath; + } + + if (array_key_exists($indexInFile, $this->inMemoryContents)) { + $escapedSharedString = $this->inMemoryContents[$indexInFile]; + $sharedString = $this->unescapeLineFeed($escapedSharedString); + } + } else { + if (is_array($this->inMemoryContents) && array_key_exists($sharedStringIndex, $this->inMemoryContents)) { + $sharedString = $this->inMemoryContents[$sharedStringIndex]; + } } if ($sharedString === null) { diff --git a/src/Spout/Reader/XLSX.php b/src/Spout/Reader/XLSX.php index 5865d20..5e8c124 100644 --- a/src/Spout/Reader/XLSX.php +++ b/src/Spout/Reader/XLSX.php @@ -32,6 +32,9 @@ class XLSX extends AbstractReader /** @var string Temporary folder where the temporary files will be created */ protected $tempFolder; + + /** @var bool Disabling this will increase your memory usage but can improve your execution time */ + protected $useSharedStringsFileCache = true; /** @var \ZipArchive */ protected $zip; @@ -63,6 +66,19 @@ class XLSX extends AbstractReader $this->tempFolder = $tempFolder; return $this; } + + /** + * Disabling the shared strings file cache will increase your memory usage but can improve your execution time. + * The shared strings file cache is active by default. + * + * @param bool $useSharedStringsFileCache + * @return XLSX + */ + public function setUseSharedStringsFileCache($useSharedStringsFileCache) + { + $this->useSharedStringsFileCache = $useSharedStringsFileCache; + return $this; + } /** * Opens the file at the given file path to make it ready to be read. @@ -80,7 +96,7 @@ class XLSX extends AbstractReader $this->zip = new \ZipArchive(); if ($this->zip->open($filePath) === true) { - $this->sharedStringsHelper = new SharedStringsHelper($filePath, $this->tempFolder); + $this->sharedStringsHelper = new SharedStringsHelper($filePath, $this->tempFolder, $this->useSharedStringsFileCache); if ($this->sharedStringsHelper->hasSharedStrings()) { // Extracts all the strings from the worksheets for easy access in the future